aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBabu Moger <babu.moger@amd.com>2018-03-16 16:37:26 -0400
committerRadim Krčmář <rkrcmar@redhat.com>2018-03-28 16:47:06 -0400
commit8566ac8b8e7cac5814fb744ff5159d1797a1a6bd (patch)
treeae30d61a9ff725180e1f290d683de6fa9aeb33cc
parent1d8fb44a728b7a34604307976a7d2a003bc84f16 (diff)
KVM: SVM: Implement pause loop exit logic in SVM
Bring the PLE(pause loop exit) logic to AMD svm driver. While testing, we found this helping in situations where numerous pauses are generated. Without these patches we could see continuos VMEXITS due to pause interceptions. Tested it on AMD EPYC server with boot parameter idle=poll on a VM with 32 vcpus to simulate extensive pause behaviour. Here are VMEXITS in 10 seconds interval. Pauses 810199 504 Total 882184 325415 Signed-off-by: Babu Moger <babu.moger@amd.com> [Prevented the window from dropping below the initial value. - Radim] Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
-rw-r--r--arch/x86/kvm/svm.c106
-rw-r--r--arch/x86/kvm/x86.h2
2 files changed, 105 insertions, 3 deletions
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 282aeff5d100..f66fc2ee9058 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -299,6 +299,54 @@ static bool npt_enabled = true;
299static bool npt_enabled; 299static bool npt_enabled;
300#endif 300#endif
301 301
302/*
303 * These 2 parameters are used to config the controls for Pause-Loop Exiting:
304 * pause_filter_count: On processors that support Pause filtering(indicated
305 * by CPUID Fn8000_000A_EDX), the VMCB provides a 16 bit pause filter
306 * count value. On VMRUN this value is loaded into an internal counter.
307 * Each time a pause instruction is executed, this counter is decremented
308 * until it reaches zero at which time a #VMEXIT is generated if pause
309 * intercept is enabled. Refer to AMD APM Vol 2 Section 15.14.4 Pause
310 * Intercept Filtering for more details.
311 * This also indicate if ple logic enabled.
312 *
313 * pause_filter_thresh: In addition, some processor families support advanced
314 * pause filtering (indicated by CPUID Fn8000_000A_EDX) upper bound on
315 * the amount of time a guest is allowed to execute in a pause loop.
316 * In this mode, a 16-bit pause filter threshold field is added in the
317 * VMCB. The threshold value is a cycle count that is used to reset the
318 * pause counter. As with simple pause filtering, VMRUN loads the pause
319 * count value from VMCB into an internal counter. Then, on each pause
320 * instruction the hardware checks the elapsed number of cycles since
321 * the most recent pause instruction against the pause filter threshold.
322 * If the elapsed cycle count is greater than the pause filter threshold,
323 * then the internal pause count is reloaded from the VMCB and execution
324 * continues. If the elapsed cycle count is less than the pause filter
325 * threshold, then the internal pause count is decremented. If the count
326 * value is less than zero and PAUSE intercept is enabled, a #VMEXIT is
327 * triggered. If advanced pause filtering is supported and pause filter
328 * threshold field is set to zero, the filter will operate in the simpler,
329 * count only mode.
330 */
331
332static unsigned short pause_filter_thresh = KVM_DEFAULT_PLE_GAP;
333module_param(pause_filter_thresh, ushort, 0444);
334
335static unsigned short pause_filter_count = KVM_SVM_DEFAULT_PLE_WINDOW;
336module_param(pause_filter_count, ushort, 0444);
337
338/* Default doubles per-vcpu window every exit. */
339static unsigned short pause_filter_count_grow = KVM_DEFAULT_PLE_WINDOW_GROW;
340module_param(pause_filter_count_grow, ushort, 0444);
341
342/* Default resets per-vcpu window every exit to pause_filter_count. */
343static unsigned short pause_filter_count_shrink = KVM_DEFAULT_PLE_WINDOW_SHRINK;
344module_param(pause_filter_count_shrink, ushort, 0444);
345
346/* Default is to compute the maximum so we can never overflow. */
347static unsigned short pause_filter_count_max = KVM_SVM_DEFAULT_PLE_WINDOW_MAX;
348module_param(pause_filter_count_max, ushort, 0444);
349
302/* allow nested paging (virtualized MMU) for all guests */ 350/* allow nested paging (virtualized MMU) for all guests */
303static int npt = true; 351static int npt = true;
304module_param(npt, int, S_IRUGO); 352module_param(npt, int, S_IRUGO);
@@ -1198,6 +1246,42 @@ err:
1198 return rc; 1246 return rc;
1199} 1247}
1200 1248
1249static void grow_ple_window(struct kvm_vcpu *vcpu)
1250{
1251 struct vcpu_svm *svm = to_svm(vcpu);
1252 struct vmcb_control_area *control = &svm->vmcb->control;
1253 int old = control->pause_filter_count;
1254
1255 control->pause_filter_count = __grow_ple_window(old,
1256 pause_filter_count,
1257 pause_filter_count_grow,
1258 pause_filter_count_max);
1259
1260 if (control->pause_filter_count != old)
1261 mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
1262
1263 trace_kvm_ple_window_grow(vcpu->vcpu_id,
1264 control->pause_filter_count, old);
1265}
1266
1267static void shrink_ple_window(struct kvm_vcpu *vcpu)
1268{
1269 struct vcpu_svm *svm = to_svm(vcpu);
1270 struct vmcb_control_area *control = &svm->vmcb->control;
1271 int old = control->pause_filter_count;
1272
1273 control->pause_filter_count =
1274 __shrink_ple_window(old,
1275 pause_filter_count,
1276 pause_filter_count_shrink,
1277 pause_filter_count);
1278 if (control->pause_filter_count != old)
1279 mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
1280
1281 trace_kvm_ple_window_shrink(vcpu->vcpu_id,
1282 control->pause_filter_count, old);
1283}
1284
1201static __init int svm_hardware_setup(void) 1285static __init int svm_hardware_setup(void)
1202{ 1286{
1203 int cpu; 1287 int cpu;
@@ -1228,6 +1312,14 @@ static __init int svm_hardware_setup(void)
1228 kvm_tsc_scaling_ratio_frac_bits = 32; 1312 kvm_tsc_scaling_ratio_frac_bits = 32;
1229 } 1313 }
1230 1314
1315 /* Check for pause filtering support */
1316 if (!boot_cpu_has(X86_FEATURE_PAUSEFILTER)) {
1317 pause_filter_count = 0;
1318 pause_filter_thresh = 0;
1319 } else if (!boot_cpu_has(X86_FEATURE_PFTHRESHOLD)) {
1320 pause_filter_thresh = 0;
1321 }
1322
1231 if (nested) { 1323 if (nested) {
1232 printk(KERN_INFO "kvm: Nested Virtualization enabled\n"); 1324 printk(KERN_INFO "kvm: Nested Virtualization enabled\n");
1233 kvm_enable_efer_bits(EFER_SVME | EFER_LMSLE); 1325 kvm_enable_efer_bits(EFER_SVME | EFER_LMSLE);
@@ -1485,10 +1577,13 @@ static void init_vmcb(struct vcpu_svm *svm)
1485 svm->nested.vmcb = 0; 1577 svm->nested.vmcb = 0;
1486 svm->vcpu.arch.hflags = 0; 1578 svm->vcpu.arch.hflags = 0;
1487 1579
1488 if (boot_cpu_has(X86_FEATURE_PAUSEFILTER) && 1580 if (pause_filter_count) {
1489 !kvm_pause_in_guest(svm->vcpu.kvm)) { 1581 control->pause_filter_count = pause_filter_count;
1490 control->pause_filter_count = 3000; 1582 if (pause_filter_thresh)
1583 control->pause_filter_thresh = pause_filter_thresh;
1491 set_intercept(svm, INTERCEPT_PAUSE); 1584 set_intercept(svm, INTERCEPT_PAUSE);
1585 } else {
1586 clr_intercept(svm, INTERCEPT_PAUSE);
1492 } 1587 }
1493 1588
1494 if (kvm_vcpu_apicv_active(&svm->vcpu)) 1589 if (kvm_vcpu_apicv_active(&svm->vcpu))
@@ -4288,6 +4383,9 @@ static int pause_interception(struct vcpu_svm *svm)
4288 struct kvm_vcpu *vcpu = &svm->vcpu; 4383 struct kvm_vcpu *vcpu = &svm->vcpu;
4289 bool in_kernel = (svm_get_cpl(vcpu) == 0); 4384 bool in_kernel = (svm_get_cpl(vcpu) == 0);
4290 4385
4386 if (pause_filter_thresh)
4387 grow_ple_window(vcpu);
4388
4291 kvm_vcpu_on_spin(vcpu, in_kernel); 4389 kvm_vcpu_on_spin(vcpu, in_kernel);
4292 return 1; 4390 return 1;
4293} 4391}
@@ -5984,6 +6082,8 @@ static void svm_handle_external_intr(struct kvm_vcpu *vcpu)
5984 6082
5985static void svm_sched_in(struct kvm_vcpu *vcpu, int cpu) 6083static void svm_sched_in(struct kvm_vcpu *vcpu, int cpu)
5986{ 6084{
6085 if (pause_filter_thresh)
6086 shrink_ple_window(vcpu);
5987} 6087}
5988 6088
5989static inline void avic_post_state_restore(struct kvm_vcpu *vcpu) 6089static inline void avic_post_state_restore(struct kvm_vcpu *vcpu)
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index 0804722b809e..42350391b62f 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -11,6 +11,8 @@
11#define KVM_DEFAULT_PLE_WINDOW_GROW 2 11#define KVM_DEFAULT_PLE_WINDOW_GROW 2
12#define KVM_DEFAULT_PLE_WINDOW_SHRINK 0 12#define KVM_DEFAULT_PLE_WINDOW_SHRINK 0
13#define KVM_VMX_DEFAULT_PLE_WINDOW_MAX UINT_MAX 13#define KVM_VMX_DEFAULT_PLE_WINDOW_MAX UINT_MAX
14#define KVM_SVM_DEFAULT_PLE_WINDOW_MAX USHRT_MAX
15#define KVM_SVM_DEFAULT_PLE_WINDOW 3000
14 16
15static inline unsigned int __grow_ple_window(unsigned int val, 17static inline unsigned int __grow_ple_window(unsigned int val,
16 unsigned int base, unsigned int modifier, unsigned int max) 18 unsigned int base, unsigned int modifier, unsigned int max)