@@ -119,6 +119,13 @@ static inline void native_flush_tlb_others(const struct cpumask *cpumask,
{
}
+static inline void kvm_flush_tlb_others(const struct cpumask *cpumask,
+ struct mm_struct *mm,
+ unsigned long start,
+ unsigned long end)
+{
+}
+
static inline void reset_lazy_tlbstate(void)
{
}
@@ -153,6 +160,10 @@ void native_flush_tlb_others(const struct cpumask *cpumask,
struct mm_struct *mm,
unsigned long start, unsigned long end);
+void kvm_flush_tlb_others(const struct cpumask *cpumask,
+ struct mm_struct *mm, unsigned long start,
+ unsigned long end);
+
#define TLBSTATE_OK 1
#define TLBSTATE_LAZY 2
@@ -501,8 +501,10 @@ void __init kvm_guest_init(void)
apic_set_eoi_write(kvm_guest_apic_eoi_write);
#ifdef CONFIG_PARAVIRT_TLB_FLUSH
- if (kvm_para_has_feature(KVM_FEATURE_VCPU_STATE))
+ if (kvm_para_has_feature(KVM_FEATURE_VCPU_STATE)) {
has_vcpu_state = 1;
+ pv_mmu_ops.flush_tlb_others = kvm_flush_tlb_others;
+ }
#endif
#ifdef CONFIG_SMP
@@ -6,6 +6,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/cpu.h>
+#include <linux/kvm_para.h>
#include <asm/tlbflush.h>
#include <asm/mmu_context.h>
@@ -119,6 +120,42 @@ static void flush_tlb_func(void *info)
}
+#ifdef CONFIG_KVM_GUEST
+
+DECLARE_PER_CPU(struct kvm_vcpu_state, vcpu_state) __aligned(64);
+
+void kvm_flush_tlb_others(const struct cpumask *cpumask,
+ struct mm_struct *mm, unsigned long start,
+ unsigned long end)
+{
+ struct flush_tlb_info info;
+ struct kvm_vcpu_state *v_state;
+ u64 state;
+ int cpu;
+ cpumask_t flushmask;
+
+ cpumask_copy(&flushmask, cpumask);
+ info.flush_mm = mm;
+ info.flush_start = start;
+ info.flush_end = end;
+ /*
+ * We have to call flush only on online vCPUs. And
+ * queue flush_on_enter for pre-empted vCPUs
+ */
+ for_each_cpu(cpu, to_cpumask(&flushmask)) {
+ v_state = &per_cpu(vcpu_state, cpu);
+ state = v_state->state;
+ if (!test_bit(KVM_VCPU_STATE_IN_GUEST_MODE, &state)) {
+ if (cmpxchg(&v_state->state, state, state | 1 << KVM_VCPU_STATE_SHOULD_FLUSH))
+ cpumask_clear_cpu(cpu, to_cpumask(&flushmask));
+ }
+ }
+
+ if (!cpumask_empty(to_cpumask(&flushmask)))
+ smp_call_function_many(&flushmask, flush_tlb_func, &info, 1);
+}
+#endif /* CONFIG_KVM_GUEST */
+
void native_flush_tlb_others(const struct cpumask *cpumask,
struct mm_struct *mm, unsigned long start,
unsigned long end)