diff options
author | Marcelo Tosatti <mtosatti@redhat.com> | 2008-02-22 12:21:38 -0500 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-04-27 05:00:28 -0400 |
commit | 096d14a3b57e4a87d27be09cc64b4f84660acd08 (patch) | |
tree | 73408f02e84397483a88fb8855fc5c5cb6687bd3 /arch/x86/kernel/kvm.c | |
parent | 1da8a77bdc294acdc37e8504926383b86f72d6be (diff) |
x86: KVM guest: hypercall batching
Batch pte updates and tlb flushes in lazy MMU mode.
[avi:
- adjust to mmu_op
- helper for getting para_state without debug warnings]
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'arch/x86/kernel/kvm.c')
-rw-r--r-- | arch/x86/kernel/kvm.c | 62 |
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 | |||
33 | struct kvm_para_state { | ||
34 | u8 mmu_queue[MMU_QUEUE_SIZE]; | ||
35 | int mmu_queue_len; | ||
36 | enum paravirt_lazy_mode mode; | ||
37 | }; | ||
38 | |||
39 | static DEFINE_PER_CPU(struct kvm_para_state, para_state); | ||
40 | |||
41 | static 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 | ||
67 | static 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 | |||
75 | static 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 | |||
51 | static void kvm_mmu_write(void *dest, u64 val) | 89 | static 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 | ||
143 | static void kvm_release_pt(u32 pfn) | 181 | static 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 | ||
191 | static 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 | |||
199 | static 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 | |||
153 | static void paravirt_ops_setup(void) | 208 | static 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 | ||