diff options
Diffstat (limited to 'arch/arm64/kvm/psci.c')
| -rw-r--r-- | arch/arm64/kvm/psci.c | 37 | 
1 files changed, 22 insertions, 15 deletions
diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c index 7fbc4c1b9df0..1f69b667332b 100644 --- a/arch/arm64/kvm/psci.c +++ b/arch/arm64/kvm/psci.c @@ -62,6 +62,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)  	struct vcpu_reset_state *reset_state;  	struct kvm *kvm = source_vcpu->kvm;  	struct kvm_vcpu *vcpu = NULL; +	int ret = PSCI_RET_SUCCESS;  	unsigned long cpu_id;  	cpu_id = smccc_get_arg1(source_vcpu); @@ -76,11 +77,15 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)  	 */  	if (!vcpu)  		return PSCI_RET_INVALID_PARAMS; + +	spin_lock(&vcpu->arch.mp_state_lock);  	if (!kvm_arm_vcpu_stopped(vcpu)) {  		if (kvm_psci_version(source_vcpu) != KVM_ARM_PSCI_0_1) -			return PSCI_RET_ALREADY_ON; +			ret = PSCI_RET_ALREADY_ON;  		else -			return PSCI_RET_INVALID_PARAMS; +			ret = PSCI_RET_INVALID_PARAMS; + +		goto out_unlock;  	}  	reset_state = &vcpu->arch.reset_state; @@ -96,7 +101,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)  	 */  	reset_state->r0 = smccc_get_arg3(source_vcpu); -	WRITE_ONCE(reset_state->reset, true); +	reset_state->reset = true;  	kvm_make_request(KVM_REQ_VCPU_RESET, vcpu);  	/* @@ -105,10 +110,12 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)  	 */  	smp_wmb(); -	vcpu->arch.mp_state.mp_state = KVM_MP_STATE_RUNNABLE; +	WRITE_ONCE(vcpu->arch.mp_state.mp_state, KVM_MP_STATE_RUNNABLE);  	kvm_vcpu_wake_up(vcpu); -	return PSCI_RET_SUCCESS; +out_unlock: +	spin_unlock(&vcpu->arch.mp_state_lock); +	return ret;  }  static unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu) @@ -168,8 +175,11 @@ static void kvm_prepare_system_event(struct kvm_vcpu *vcpu, u32 type, u64 flags)  	 * after this call is handled and before the VCPUs have been  	 * re-initialized.  	 */ -	kvm_for_each_vcpu(i, tmp, vcpu->kvm) -		tmp->arch.mp_state.mp_state = KVM_MP_STATE_STOPPED; +	kvm_for_each_vcpu(i, tmp, vcpu->kvm) { +		spin_lock(&tmp->arch.mp_state_lock); +		WRITE_ONCE(tmp->arch.mp_state.mp_state, KVM_MP_STATE_STOPPED); +		spin_unlock(&tmp->arch.mp_state_lock); +	}  	kvm_make_all_cpus_request(vcpu->kvm, KVM_REQ_SLEEP);  	memset(&vcpu->run->system_event, 0, sizeof(vcpu->run->system_event)); @@ -229,7 +239,6 @@ static unsigned long kvm_psci_check_allowed_function(struct kvm_vcpu *vcpu, u32  static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)  { -	struct kvm *kvm = vcpu->kvm;  	u32 psci_fn = smccc_get_function(vcpu);  	unsigned long val;  	int ret = 1; @@ -254,9 +263,7 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)  		kvm_psci_narrow_to_32bit(vcpu);  		fallthrough;  	case PSCI_0_2_FN64_CPU_ON: -		mutex_lock(&kvm->lock);  		val = kvm_psci_vcpu_on(vcpu); -		mutex_unlock(&kvm->lock);  		break;  	case PSCI_0_2_FN_AFFINITY_INFO:  		kvm_psci_narrow_to_32bit(vcpu); @@ -395,7 +402,6 @@ static int kvm_psci_1_x_call(struct kvm_vcpu *vcpu, u32 minor)  static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)  { -	struct kvm *kvm = vcpu->kvm;  	u32 psci_fn = smccc_get_function(vcpu);  	unsigned long val; @@ -405,9 +411,7 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)  		val = PSCI_RET_SUCCESS;  		break;  	case KVM_PSCI_FN_CPU_ON: -		mutex_lock(&kvm->lock);  		val = kvm_psci_vcpu_on(vcpu); -		mutex_unlock(&kvm->lock);  		break;  	default:  		val = PSCI_RET_NOT_SUPPORTED; @@ -435,6 +439,7 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)  int kvm_psci_call(struct kvm_vcpu *vcpu)  {  	u32 psci_fn = smccc_get_function(vcpu); +	int version = kvm_psci_version(vcpu);  	unsigned long val;  	val = kvm_psci_check_allowed_function(vcpu, psci_fn); @@ -443,7 +448,7 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)  		return 1;  	} -	switch (kvm_psci_version(vcpu)) { +	switch (version) {  	case KVM_ARM_PSCI_1_1:  		return kvm_psci_1_x_call(vcpu, 1);  	case KVM_ARM_PSCI_1_0: @@ -453,6 +458,8 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)  	case KVM_ARM_PSCI_0_1:  		return kvm_psci_0_1_call(vcpu);  	default: -		return -EINVAL; +		WARN_ONCE(1, "Unknown PSCI version %d", version); +		smccc_set_retval(vcpu, SMCCC_RET_NOT_SUPPORTED, 0, 0, 0); +		return 1;  	}  }  |