aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/kvm.c62
1 files changed, 60 insertions, 2 deletions
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index cbadc730496a..8b7a3cf37d2b 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -26,6 +26,22 @@
26#include <linux/cpu.h> 26#include <linux/cpu.h>
27#include <linux/mm.h> 27#include <linux/mm.h>
28#include <linux/highmem.h> 28#include <linux/highmem.h>
29#include <linux/hardirq.h>
30
31#define MMU_QUEUE_SIZE 1024
32
33struct kvm_para_state {
34 u8 mmu_queue[MMU_QUEUE_SIZE];
35 int mmu_queue_len;
36 enum paravirt_lazy_mode mode;
37};
38
39static DEFINE_PER_CPU(struct kvm_para_state, para_state);
40
41static struct kvm_para_state *kvm_para_state(void)
42{
43 return &per_cpu(para_state, raw_smp_processor_id());
44}
29 45
30/* 46/*
31 * No need for any "IO delay" on KVM 47 * No need for any "IO delay" on KVM
@@ -48,6 +64,28 @@ static void kvm_mmu_op(void *buffer, unsigned len)
48 } while (len); 64 } while (len);
49} 65}
50 66
67static void mmu_queue_flush(struct kvm_para_state *state)
68{
69 if (state->mmu_queue_len) {
70 kvm_mmu_op(state->mmu_queue, state->mmu_queue_len);
71 state->mmu_queue_len = 0;
72 }
73}
74
75static void kvm_deferred_mmu_op(void *buffer, int len)
76{
77 struct kvm_para_state *state = kvm_para_state();
78
79 if (state->mode != PARAVIRT_LAZY_MMU) {
80 kvm_mmu_op(buffer, len);
81 return;
82 }
83 if (state->mmu_queue_len + len > sizeof state->mmu_queue)
84 mmu_queue_flush(state);
85 memcpy(state->mmu_queue + state->mmu_queue_len, buffer, len);
86 state->mmu_queue_len += len;
87}
88
51static void kvm_mmu_write(void *dest, u64 val) 89static void kvm_mmu_write(void *dest, u64 val)
52{ 90{
53 __u64 pte_phys; 91 __u64 pte_phys;
@@ -68,7 +106,7 @@ static void kvm_mmu_write(void *dest, u64 val)
68 wpte.pte_val = val; 106 wpte.pte_val = val;
69 wpte.pte_phys = pte_phys; 107 wpte.pte_phys = pte_phys;
70 108
71 kvm_mmu_op(&wpte, sizeof wpte); 109 kvm_deferred_mmu_op(&wpte, sizeof wpte);
72} 110}
73 111
74/* 112/*
@@ -137,7 +175,7 @@ static void kvm_flush_tlb(void)
137 .header.op = KVM_MMU_OP_FLUSH_TLB, 175 .header.op = KVM_MMU_OP_FLUSH_TLB,
138 }; 176 };
139 177
140 kvm_mmu_op(&ftlb, sizeof ftlb); 178 kvm_deferred_mmu_op(&ftlb, sizeof ftlb);
141} 179}
142 180
143static void kvm_release_pt(u32 pfn) 181static void kvm_release_pt(u32 pfn)
@@ -150,6 +188,23 @@ static void kvm_release_pt(u32 pfn)
150 kvm_mmu_op(&rpt, sizeof rpt); 188 kvm_mmu_op(&rpt, sizeof rpt);
151} 189}
152 190
191static void kvm_enter_lazy_mmu(void)
192{
193 struct kvm_para_state *state = kvm_para_state();
194
195 paravirt_enter_lazy_mmu();
196 state->mode = paravirt_get_lazy_mode();
197}
198
199static void kvm_leave_lazy_mmu(void)
200{
201 struct kvm_para_state *state = kvm_para_state();
202
203 mmu_queue_flush(state);
204 paravirt_leave_lazy(paravirt_get_lazy_mode());
205 state->mode = paravirt_get_lazy_mode();
206}
207
153static void paravirt_ops_setup(void) 208static void paravirt_ops_setup(void)
154{ 209{
155 pv_info.name = "KVM"; 210 pv_info.name = "KVM";
@@ -178,6 +233,9 @@ static void paravirt_ops_setup(void)
178 pv_mmu_ops.release_pte = kvm_release_pt; 233 pv_mmu_ops.release_pte = kvm_release_pt;
179 pv_mmu_ops.release_pmd = kvm_release_pt; 234 pv_mmu_ops.release_pmd = kvm_release_pt;
180 pv_mmu_ops.release_pud = kvm_release_pt; 235 pv_mmu_ops.release_pud = kvm_release_pt;
236
237 pv_mmu_ops.lazy_mode.enter = kvm_enter_lazy_mmu;
238 pv_mmu_ops.lazy_mode.leave = kvm_leave_lazy_mmu;
181 } 239 }
182} 240}
183 241