xref: /openbmc/linux/arch/riscv/kvm/vcpu_sbi_hsm.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
13e1d8656SAtish Patra // SPDX-License-Identifier: GPL-2.0
23e1d8656SAtish Patra /*
33e1d8656SAtish Patra  * Copyright (c) 2021 Western Digital Corporation or its affiliates.
43e1d8656SAtish Patra  *
53e1d8656SAtish Patra  * Authors:
63e1d8656SAtish Patra  *     Atish Patra <atish.patra@wdc.com>
73e1d8656SAtish Patra  */
83e1d8656SAtish Patra 
93e1d8656SAtish Patra #include <linux/errno.h>
103e1d8656SAtish Patra #include <linux/err.h>
113e1d8656SAtish Patra #include <linux/kvm_host.h>
123e1d8656SAtish Patra #include <asm/sbi.h>
133e1d8656SAtish Patra #include <asm/kvm_vcpu_sbi.h>
143e1d8656SAtish Patra 
kvm_sbi_hsm_vcpu_start(struct kvm_vcpu * vcpu)153e1d8656SAtish Patra static int kvm_sbi_hsm_vcpu_start(struct kvm_vcpu *vcpu)
163e1d8656SAtish Patra {
173e1d8656SAtish Patra 	struct kvm_cpu_context *reset_cntx;
183e1d8656SAtish Patra 	struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
193e1d8656SAtish Patra 	struct kvm_vcpu *target_vcpu;
203e1d8656SAtish Patra 	unsigned long target_vcpuid = cp->a0;
213e1d8656SAtish Patra 
223e1d8656SAtish Patra 	target_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, target_vcpuid);
233e1d8656SAtish Patra 	if (!target_vcpu)
24*bae0dfd7SAtish Patra 		return SBI_ERR_INVALID_PARAM;
253e1d8656SAtish Patra 	if (!target_vcpu->arch.power_off)
26*bae0dfd7SAtish Patra 		return SBI_ERR_ALREADY_AVAILABLE;
273e1d8656SAtish Patra 
283e1d8656SAtish Patra 	reset_cntx = &target_vcpu->arch.guest_reset_context;
293e1d8656SAtish Patra 	/* start address */
303e1d8656SAtish Patra 	reset_cntx->sepc = cp->a1;
313e1d8656SAtish Patra 	/* target vcpu id to start */
323e1d8656SAtish Patra 	reset_cntx->a0 = target_vcpuid;
333e1d8656SAtish Patra 	/* private data passed from kernel */
343e1d8656SAtish Patra 	reset_cntx->a1 = cp->a2;
353e1d8656SAtish Patra 	kvm_make_request(KVM_REQ_VCPU_RESET, target_vcpu);
363e1d8656SAtish Patra 
373e1d8656SAtish Patra 	kvm_riscv_vcpu_power_on(target_vcpu);
383e1d8656SAtish Patra 
393e1d8656SAtish Patra 	return 0;
403e1d8656SAtish Patra }
413e1d8656SAtish Patra 
kvm_sbi_hsm_vcpu_stop(struct kvm_vcpu * vcpu)423e1d8656SAtish Patra static int kvm_sbi_hsm_vcpu_stop(struct kvm_vcpu *vcpu)
433e1d8656SAtish Patra {
443e1d8656SAtish Patra 	if (vcpu->arch.power_off)
45*bae0dfd7SAtish Patra 		return SBI_ERR_FAILURE;
463e1d8656SAtish Patra 
473e1d8656SAtish Patra 	kvm_riscv_vcpu_power_off(vcpu);
483e1d8656SAtish Patra 
493e1d8656SAtish Patra 	return 0;
503e1d8656SAtish Patra }
513e1d8656SAtish Patra 
kvm_sbi_hsm_vcpu_get_status(struct kvm_vcpu * vcpu)523e1d8656SAtish Patra static int kvm_sbi_hsm_vcpu_get_status(struct kvm_vcpu *vcpu)
533e1d8656SAtish Patra {
543e1d8656SAtish Patra 	struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
553e1d8656SAtish Patra 	unsigned long target_vcpuid = cp->a0;
563e1d8656SAtish Patra 	struct kvm_vcpu *target_vcpu;
573e1d8656SAtish Patra 
583e1d8656SAtish Patra 	target_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, target_vcpuid);
593e1d8656SAtish Patra 	if (!target_vcpu)
60*bae0dfd7SAtish Patra 		return SBI_ERR_INVALID_PARAM;
613e1d8656SAtish Patra 	if (!target_vcpu->arch.power_off)
62c38ff47bSAnup Patel 		return SBI_HSM_STATE_STARTED;
63763c8bedSAnup Patel 	else if (vcpu->stat.generic.blocking)
64763c8bedSAnup Patel 		return SBI_HSM_STATE_SUSPENDED;
653e1d8656SAtish Patra 	else
66c38ff47bSAnup Patel 		return SBI_HSM_STATE_STOPPED;
673e1d8656SAtish Patra }
683e1d8656SAtish Patra 
kvm_sbi_ext_hsm_handler(struct kvm_vcpu * vcpu,struct kvm_run * run,struct kvm_vcpu_sbi_return * retdata)693e1d8656SAtish Patra static int kvm_sbi_ext_hsm_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
70*bae0dfd7SAtish Patra 				   struct kvm_vcpu_sbi_return *retdata)
713e1d8656SAtish Patra {
723e1d8656SAtish Patra 	int ret = 0;
733e1d8656SAtish Patra 	struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
743e1d8656SAtish Patra 	struct kvm *kvm = vcpu->kvm;
753e1d8656SAtish Patra 	unsigned long funcid = cp->a6;
763e1d8656SAtish Patra 
773e1d8656SAtish Patra 	switch (funcid) {
783e1d8656SAtish Patra 	case SBI_EXT_HSM_HART_START:
793e1d8656SAtish Patra 		mutex_lock(&kvm->lock);
803e1d8656SAtish Patra 		ret = kvm_sbi_hsm_vcpu_start(vcpu);
813e1d8656SAtish Patra 		mutex_unlock(&kvm->lock);
823e1d8656SAtish Patra 		break;
833e1d8656SAtish Patra 	case SBI_EXT_HSM_HART_STOP:
843e1d8656SAtish Patra 		ret = kvm_sbi_hsm_vcpu_stop(vcpu);
853e1d8656SAtish Patra 		break;
863e1d8656SAtish Patra 	case SBI_EXT_HSM_HART_STATUS:
873e1d8656SAtish Patra 		ret = kvm_sbi_hsm_vcpu_get_status(vcpu);
883e1d8656SAtish Patra 		if (ret >= 0) {
89*bae0dfd7SAtish Patra 			retdata->out_val = ret;
90*bae0dfd7SAtish Patra 			retdata->err_val = 0;
913e1d8656SAtish Patra 		}
92*bae0dfd7SAtish Patra 		return 0;
93763c8bedSAnup Patel 	case SBI_EXT_HSM_HART_SUSPEND:
94763c8bedSAnup Patel 		switch (cp->a0) {
95763c8bedSAnup Patel 		case SBI_HSM_SUSPEND_RET_DEFAULT:
96763c8bedSAnup Patel 			kvm_riscv_vcpu_wfi(vcpu);
97763c8bedSAnup Patel 			break;
98763c8bedSAnup Patel 		case SBI_HSM_SUSPEND_NON_RET_DEFAULT:
99*bae0dfd7SAtish Patra 			ret = SBI_ERR_NOT_SUPPORTED;
100763c8bedSAnup Patel 			break;
101763c8bedSAnup Patel 		default:
102*bae0dfd7SAtish Patra 			ret = SBI_ERR_INVALID_PARAM;
103763c8bedSAnup Patel 		}
104763c8bedSAnup Patel 		break;
1053e1d8656SAtish Patra 	default:
106*bae0dfd7SAtish Patra 		ret = SBI_ERR_NOT_SUPPORTED;
1073e1d8656SAtish Patra 	}
1083e1d8656SAtish Patra 
109*bae0dfd7SAtish Patra 	retdata->err_val = ret;
110*bae0dfd7SAtish Patra 
111*bae0dfd7SAtish Patra 	return 0;
1123e1d8656SAtish Patra }
1133e1d8656SAtish Patra 
1143e1d8656SAtish Patra const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_hsm = {
1153e1d8656SAtish Patra 	.extid_start = SBI_EXT_HSM,
1163e1d8656SAtish Patra 	.extid_end = SBI_EXT_HSM,
1173e1d8656SAtish Patra 	.handler = kvm_sbi_ext_hsm_handler,
1183e1d8656SAtish Patra };
119