KVM paravirt: Add async PF initialization to PV guest.
Enable async PF in a guest if async PF capability is discovered. Acked-by: Rik van Riel <riel@redhat.com> Signed-off-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
This commit is contained in:
		
					parent
					
						
							
								344d9588a9
							
						
					
				
			
			
				commit
				
					
						fd10cde929
					
				
			
		
					 3 changed files with 101 additions and 0 deletions
				
			
		|  | @ -1707,6 +1707,9 @@ and is between 256 and 4096 characters. It is defined in the file | ||||||
| 
 | 
 | ||||||
| 	no-kvmclock	[X86,KVM] Disable paravirtualized KVM clock driver | 	no-kvmclock	[X86,KVM] Disable paravirtualized KVM clock driver | ||||||
| 
 | 
 | ||||||
|  | 	no-kvmapf	[X86,KVM] Disable paravirtualized asynchronous page | ||||||
|  | 			fault handling. | ||||||
|  | 
 | ||||||
| 	nolapic		[X86-32,APIC] Do not enable or use the local APIC. | 	nolapic		[X86-32,APIC] Do not enable or use the local APIC. | ||||||
| 
 | 
 | ||||||
| 	nolapic_timer	[X86-32,APIC] Do not use the local APIC timer. | 	nolapic_timer	[X86-32,APIC] Do not use the local APIC timer. | ||||||
|  |  | ||||||
|  | @ -65,6 +65,12 @@ struct kvm_mmu_op_release_pt { | ||||||
| 	__u64 pt_phys; | 	__u64 pt_phys; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct kvm_vcpu_pv_apf_data { | ||||||
|  | 	__u32 reason; | ||||||
|  | 	__u8 pad[60]; | ||||||
|  | 	__u32 enabled; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| #ifdef __KERNEL__ | #ifdef __KERNEL__ | ||||||
| #include <asm/processor.h> | #include <asm/processor.h> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -27,16 +27,30 @@ | ||||||
| #include <linux/mm.h> | #include <linux/mm.h> | ||||||
| #include <linux/highmem.h> | #include <linux/highmem.h> | ||||||
| #include <linux/hardirq.h> | #include <linux/hardirq.h> | ||||||
|  | #include <linux/notifier.h> | ||||||
|  | #include <linux/reboot.h> | ||||||
| #include <asm/timer.h> | #include <asm/timer.h> | ||||||
|  | #include <asm/cpu.h> | ||||||
| 
 | 
 | ||||||
| #define MMU_QUEUE_SIZE 1024 | #define MMU_QUEUE_SIZE 1024 | ||||||
| 
 | 
 | ||||||
|  | static int kvmapf = 1; | ||||||
|  | 
 | ||||||
|  | static int parse_no_kvmapf(char *arg) | ||||||
|  | { | ||||||
|  |         kvmapf = 0; | ||||||
|  |         return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | early_param("no-kvmapf", parse_no_kvmapf); | ||||||
|  | 
 | ||||||
| struct kvm_para_state { | struct kvm_para_state { | ||||||
| 	u8 mmu_queue[MMU_QUEUE_SIZE]; | 	u8 mmu_queue[MMU_QUEUE_SIZE]; | ||||||
| 	int mmu_queue_len; | 	int mmu_queue_len; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static DEFINE_PER_CPU(struct kvm_para_state, para_state); | static DEFINE_PER_CPU(struct kvm_para_state, para_state); | ||||||
|  | static DEFINE_PER_CPU(struct kvm_vcpu_pv_apf_data, apf_reason) __aligned(64); | ||||||
| 
 | 
 | ||||||
| static struct kvm_para_state *kvm_para_state(void) | static struct kvm_para_state *kvm_para_state(void) | ||||||
| { | { | ||||||
|  | @ -231,12 +245,86 @@ static void __init paravirt_ops_setup(void) | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void __cpuinit kvm_guest_cpu_init(void) | ||||||
|  | { | ||||||
|  | 	if (!kvm_para_available()) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	if (kvm_para_has_feature(KVM_FEATURE_ASYNC_PF) && kvmapf) { | ||||||
|  | 		u64 pa = __pa(&__get_cpu_var(apf_reason)); | ||||||
|  | 
 | ||||||
|  | 		wrmsrl(MSR_KVM_ASYNC_PF_EN, pa | KVM_ASYNC_PF_ENABLED); | ||||||
|  | 		__get_cpu_var(apf_reason).enabled = 1; | ||||||
|  | 		printk(KERN_INFO"KVM setup async PF for cpu %d\n", | ||||||
|  | 		       smp_processor_id()); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void kvm_pv_disable_apf(void *unused) | ||||||
|  | { | ||||||
|  | 	if (!__get_cpu_var(apf_reason).enabled) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	wrmsrl(MSR_KVM_ASYNC_PF_EN, 0); | ||||||
|  | 	__get_cpu_var(apf_reason).enabled = 0; | ||||||
|  | 
 | ||||||
|  | 	printk(KERN_INFO"Unregister pv shared memory for cpu %d\n", | ||||||
|  | 	       smp_processor_id()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int kvm_pv_reboot_notify(struct notifier_block *nb, | ||||||
|  | 				unsigned long code, void *unused) | ||||||
|  | { | ||||||
|  | 	if (code == SYS_RESTART) | ||||||
|  | 		on_each_cpu(kvm_pv_disable_apf, NULL, 1); | ||||||
|  | 	return NOTIFY_DONE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static struct notifier_block kvm_pv_reboot_nb = { | ||||||
|  | 	.notifier_call = kvm_pv_reboot_notify, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| #ifdef CONFIG_SMP | #ifdef CONFIG_SMP | ||||||
| static void __init kvm_smp_prepare_boot_cpu(void) | static void __init kvm_smp_prepare_boot_cpu(void) | ||||||
| { | { | ||||||
| 	WARN_ON(kvm_register_clock("primary cpu clock")); | 	WARN_ON(kvm_register_clock("primary cpu clock")); | ||||||
|  | 	kvm_guest_cpu_init(); | ||||||
| 	native_smp_prepare_boot_cpu(); | 	native_smp_prepare_boot_cpu(); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | static void kvm_guest_cpu_online(void *dummy) | ||||||
|  | { | ||||||
|  | 	kvm_guest_cpu_init(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void kvm_guest_cpu_offline(void *dummy) | ||||||
|  | { | ||||||
|  | 	kvm_pv_disable_apf(NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int __cpuinit kvm_cpu_notify(struct notifier_block *self, | ||||||
|  | 				    unsigned long action, void *hcpu) | ||||||
|  | { | ||||||
|  | 	int cpu = (unsigned long)hcpu; | ||||||
|  | 	switch (action) { | ||||||
|  | 	case CPU_ONLINE: | ||||||
|  | 	case CPU_DOWN_FAILED: | ||||||
|  | 	case CPU_ONLINE_FROZEN: | ||||||
|  | 		smp_call_function_single(cpu, kvm_guest_cpu_online, NULL, 0); | ||||||
|  | 		break; | ||||||
|  | 	case CPU_DOWN_PREPARE: | ||||||
|  | 	case CPU_DOWN_PREPARE_FROZEN: | ||||||
|  | 		smp_call_function_single(cpu, kvm_guest_cpu_offline, NULL, 1); | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | 	return NOTIFY_OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static struct notifier_block __cpuinitdata kvm_cpu_notifier = { | ||||||
|  |         .notifier_call  = kvm_cpu_notify, | ||||||
|  | }; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| void __init kvm_guest_init(void) | void __init kvm_guest_init(void) | ||||||
|  | @ -245,7 +333,11 @@ void __init kvm_guest_init(void) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	paravirt_ops_setup(); | 	paravirt_ops_setup(); | ||||||
|  | 	register_reboot_notifier(&kvm_pv_reboot_nb); | ||||||
| #ifdef CONFIG_SMP | #ifdef CONFIG_SMP | ||||||
| 	smp_ops.smp_prepare_boot_cpu = kvm_smp_prepare_boot_cpu; | 	smp_ops.smp_prepare_boot_cpu = kvm_smp_prepare_boot_cpu; | ||||||
|  | 	register_cpu_notifier(&kvm_cpu_notifier); | ||||||
|  | #else | ||||||
|  | 	kvm_guest_cpu_init(); | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Gleb Natapov
				Gleb Natapov