diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index b2e11f4..b54f38b 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -569,6 +569,8 @@ struct kvm_arch {
 	#ifdef CONFIG_KVM_MMU_AUDIT
 	int audit_point;
 	#endif
+	int ple_gap;
+	int ple_window;
 };
 
 struct kvm_vm_stat {
@@ -621,6 +623,10 @@ struct kvm_x86_ops {
 	int (*hardware_setup)(void);               /* __init */
 	void (*hardware_unsetup)(void);            /* __exit */
 	bool (*cpu_has_accelerated_tpr)(void);
+	bool (*cpu_has_ple)(void);
+	void (*ple_setup)(struct kvm *kvm);                   /* __init */
+	void (*set_ple_gap)(struct kvm *kvm, int value);
+	void (*set_ple_window)(struct kvm *kvm, int value);
 	void (*cpuid_update)(struct kvm_vcpu *vcpu);
 
 	/* Create, but do not attach this VCPU */
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index d017df3..311ed96 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -3976,6 +3976,23 @@ static bool svm_cpu_has_accelerated_tpr(void)
 	return false;
 }
 
+static bool cpu_has_svm_ple(void)
+{
+	return false;
+}
+
+static void svm_ple_setup(struct kvm *kvm)
+{
+}
+
+static void svm_set_ple_gap(struct kvm *kvm, int value)
+{
+}
+
+static void svm_set_ple_window(struct kvm *kvm, int value)
+{
+}
+
 static u64 svm_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
 {
 	return 0;
@@ -4229,6 +4246,10 @@ static struct kvm_x86_ops svm_x86_ops = {
 	.hardware_enable = svm_hardware_enable,
 	.hardware_disable = svm_hardware_disable,
 	.cpu_has_accelerated_tpr = svm_cpu_has_accelerated_tpr,
+	.cpu_has_ple = cpu_has_svm_ple,
+	.ple_setup = svm_ple_setup,
+	.set_ple_gap = svm_set_ple_gap,
+	.set_ple_window = svm_set_ple_window,
 
 	.vcpu_create = svm_create_vcpu,
 	.vcpu_free = svm_free_vcpu,
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index ad6b1dd..b761669 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -3805,6 +3805,29 @@ static void ept_set_mmio_spte_mask(void)
 	kvm_mmu_set_mmio_spte_mask(0xffull << 49 | 0x6ull);
 }
 
+static void vmx_ple_setup(struct kvm *kvm)
+{
+	/*
+	 * set up ple default value
+	 */
+	if (ple_gap) {
+		kvm->arch.ple_gap = ple_gap;
+		kvm->arch.ple_window = ple_window;
+	}
+}
+
+static void vmx_set_ple_gap(struct kvm *kvm, int value)
+{
+	if (ple_gap)
+		kvm->arch.ple_gap = value;
+}
+
+static void vmx_set_ple_window(struct kvm *kvm, int value)
+{
+	if (ple_gap)
+		kvm->arch.ple_window = value;
+}
+
 /*
  * Sets up the vmcs for emulated real mode.
  */
@@ -3814,6 +3837,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
 	unsigned long a;
 #endif
 	int i;
+	struct kvm *kvm = vmx->vcpu.kvm;
 
 	/* I/O */
 	vmcs_write64(IO_BITMAP_A, __pa(vmx_io_bitmap_a));
@@ -3836,8 +3860,8 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
 	}
 
 	if (ple_gap) {
-		vmcs_write32(PLE_GAP, ple_gap);
-		vmcs_write32(PLE_WINDOW, ple_window);
+		vmcs_write32(PLE_GAP, kvm->arch.ple_gap);
+		vmcs_write32(PLE_WINDOW, kvm->arch.ple_window);
 	}
 
 	vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0);
@@ -7233,6 +7257,10 @@ static struct kvm_x86_ops vmx_x86_ops = {
 	.hardware_enable = hardware_enable,
 	.hardware_disable = hardware_disable,
 	.cpu_has_accelerated_tpr = report_flexpriority,
+	.cpu_has_ple = cpu_has_vmx_ple,
+	.ple_setup = vmx_ple_setup,
+	.set_ple_gap = vmx_set_ple_gap,
+	.set_ple_window = vmx_set_ple_window,
 
 	.vcpu_create = vmx_create_vcpu,
 	.vcpu_free = vmx_free_vcpu,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 1eefebe..89b8291 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2197,6 +2197,9 @@ int kvm_dev_ioctl_check_extension(long ext)
 	case KVM_CAP_VAPIC:
 		r = !kvm_x86_ops->cpu_has_accelerated_tpr();
 		break;
+	case KVM_CAP_PLE:
+		r = kvm_x86_ops->cpu_has_ple();
+		break;
 	case KVM_CAP_NR_VCPUS:
 		r = KVM_SOFT_MAX_VCPUS;
 		break;
@@ -3462,7 +3465,16 @@ long kvm_arch_vm_ioctl(struct file *filp,
 		r = 0;
 		break;
 	}
-
+	case KVM_SET_PLE_GAP: {
+		kvm_x86_ops->set_ple_gap(kvm, arg);
+		r = 0;
+		break;
+	}
+	case KVM_SET_PLE_WINDOW: {
+		kvm_x86_ops->set_ple_window(kvm, arg);
+		r = 0;
+		break;
+	}
 	default:
 		;
 	}
@@ -6295,6 +6307,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 	raw_spin_lock_init(&kvm->arch.tsc_write_lock);
 	mutex_init(&kvm->arch.apic_map_lock);
 
+	kvm_x86_ops->ple_setup(kvm);
 	return 0;
 }
 
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 0a6d6ba..02d499e 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -626,6 +626,7 @@ struct kvm_ppc_smmu_info {
 #define KVM_CAP_READONLY_MEM 81
 #endif
 #define KVM_CAP_IRQFD_RESAMPLE 82
+#define KVM_CAP_PLE 83
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -786,6 +787,8 @@ struct kvm_msi {
 					struct kvm_userspace_memory_region)
 #define KVM_SET_TSS_ADDR          _IO(KVMIO,   0x47)
 #define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO,  0x48, __u64)
+#define KVM_SET_PLE_GAP           _IOW(KVMIO,  0x49, __u32)
+#define KVM_SET_PLE_WINDOW        _IOW(KVMIO,  0x4a, __u32)
 
 /* enable ucontrol for s390 */
 struct kvm_s390_ucas_mapping {
