diff options
Diffstat (limited to 'arch/arm/kvm/arm.c')
| -rw-r--r-- | arch/arm/kvm/arm.c | 79 | 
1 files changed, 64 insertions, 15 deletions
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 2a700e00528d..1d8248ea5669 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -17,6 +17,7 @@   */  #include <linux/cpu.h> +#include <linux/cpu_pm.h>  #include <linux/errno.h>  #include <linux/err.h>  #include <linux/kvm_host.h> @@ -137,6 +138,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)  	if (ret)  		goto out_free_stage2_pgd; +	kvm_timer_init(kvm); +  	/* Mark the initial VMID generation invalid */  	kvm->arch.vmid_gen = 0; @@ -188,6 +191,7 @@ int kvm_dev_ioctl_check_extension(long ext)  	case KVM_CAP_IRQCHIP:  		r = vgic_present;  		break; +	case KVM_CAP_DEVICE_CTRL:  	case KVM_CAP_USER_MEMORY:  	case KVM_CAP_SYNC_MMU:  	case KVM_CAP_DESTROY_MEMORY_REGION_WORKS: @@ -339,6 +343,13 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)  void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)  { +	/* +	 * The arch-generic KVM code expects the cpu field of a vcpu to be -1 +	 * if the vcpu is no longer assigned to a cpu.  This is used for the +	 * optimized make_all_cpus_request path. +	 */ +	vcpu->cpu = -1; +  	kvm_arm_set_running_vcpu(NULL);  } @@ -462,6 +473,8 @@ static void update_vttbr(struct kvm *kvm)  static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)  { +	int ret; +  	if (likely(vcpu->arch.has_run_once))  		return 0; @@ -471,22 +484,12 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)  	 * Initialize the VGIC before running a vcpu the first time on  	 * this VM.  	 */ -	if (irqchip_in_kernel(vcpu->kvm) && -	    unlikely(!vgic_initialized(vcpu->kvm))) { -		int ret = kvm_vgic_init(vcpu->kvm); +	if (unlikely(!vgic_initialized(vcpu->kvm))) { +		ret = kvm_vgic_init(vcpu->kvm);  		if (ret)  			return ret;  	} -	/* -	 * Handle the "start in power-off" case by calling into the -	 * PSCI code. -	 */ -	if (test_and_clear_bit(KVM_ARM_VCPU_POWER_OFF, vcpu->arch.features)) { -		*vcpu_reg(vcpu, 0) = KVM_PSCI_FN_CPU_OFF; -		kvm_psci_call(vcpu); -	} -  	return 0;  } @@ -700,6 +703,24 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,  	return -EINVAL;  } +static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu, +					 struct kvm_vcpu_init *init) +{ +	int ret; + +	ret = kvm_vcpu_set_target(vcpu, init); +	if (ret) +		return ret; + +	/* +	 * Handle the "start in power-off" case by marking the VCPU as paused. +	 */ +	if (__test_and_clear_bit(KVM_ARM_VCPU_POWER_OFF, vcpu->arch.features)) +		vcpu->arch.pause = true; + +	return 0; +} +  long kvm_arch_vcpu_ioctl(struct file *filp,  			 unsigned int ioctl, unsigned long arg)  { @@ -713,8 +734,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,  		if (copy_from_user(&init, argp, sizeof(init)))  			return -EFAULT; -		return kvm_vcpu_set_target(vcpu, &init); - +		return kvm_arch_vcpu_ioctl_vcpu_init(vcpu, &init);  	}  	case KVM_SET_ONE_REG:  	case KVM_GET_ONE_REG: { @@ -772,7 +792,7 @@ static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,  	case KVM_ARM_DEVICE_VGIC_V2:  		if (!vgic_present)  			return -ENXIO; -		return kvm_vgic_set_addr(kvm, type, dev_addr->addr); +		return kvm_vgic_addr(kvm, type, &dev_addr->addr, true);  	default:  		return -ENODEV;  	} @@ -853,6 +873,33 @@ static struct notifier_block hyp_init_cpu_nb = {  	.notifier_call = hyp_init_cpu_notify,  }; +#ifdef CONFIG_CPU_PM +static int hyp_init_cpu_pm_notifier(struct notifier_block *self, +				    unsigned long cmd, +				    void *v) +{ +	if (cmd == CPU_PM_EXIT) { +		cpu_init_hyp_mode(NULL); +		return NOTIFY_OK; +	} + +	return NOTIFY_DONE; +} + +static struct notifier_block hyp_init_cpu_pm_nb = { +	.notifier_call = hyp_init_cpu_pm_notifier, +}; + +static void __init hyp_cpu_pm_init(void) +{ +	cpu_pm_register_notifier(&hyp_init_cpu_pm_nb); +} +#else +static inline void hyp_cpu_pm_init(void) +{ +} +#endif +  /**   * Inits Hyp-mode on all online CPUs   */ @@ -1013,6 +1060,8 @@ int kvm_arch_init(void *opaque)  		goto out_err;  	} +	hyp_cpu_pm_init(); +  	kvm_coproc_table_init();  	return 0;  out_err:  |