xref: /openbmc/linux/arch/riscv/kvm/vcpu_sbi_hsm.c (revision 763c8bed8c05ffcce8cba882e69cd6b03df07019)
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/csr.h>
133e1d8656SAtish Patra #include <asm/sbi.h>
143e1d8656SAtish Patra #include <asm/kvm_vcpu_sbi.h>
153e1d8656SAtish Patra 
163e1d8656SAtish Patra static int kvm_sbi_hsm_vcpu_start(struct kvm_vcpu *vcpu)
173e1d8656SAtish Patra {
183e1d8656SAtish Patra 	struct kvm_cpu_context *reset_cntx;
193e1d8656SAtish Patra 	struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
203e1d8656SAtish Patra 	struct kvm_vcpu *target_vcpu;
213e1d8656SAtish Patra 	unsigned long target_vcpuid = cp->a0;
223e1d8656SAtish Patra 
233e1d8656SAtish Patra 	target_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, target_vcpuid);
243e1d8656SAtish Patra 	if (!target_vcpu)
253e1d8656SAtish Patra 		return -EINVAL;
263e1d8656SAtish Patra 	if (!target_vcpu->arch.power_off)
273e1d8656SAtish Patra 		return -EALREADY;
283e1d8656SAtish Patra 
293e1d8656SAtish Patra 	reset_cntx = &target_vcpu->arch.guest_reset_context;
303e1d8656SAtish Patra 	/* start address */
313e1d8656SAtish Patra 	reset_cntx->sepc = cp->a1;
323e1d8656SAtish Patra 	/* target vcpu id to start */
333e1d8656SAtish Patra 	reset_cntx->a0 = target_vcpuid;
343e1d8656SAtish Patra 	/* private data passed from kernel */
353e1d8656SAtish Patra 	reset_cntx->a1 = cp->a2;
363e1d8656SAtish Patra 	kvm_make_request(KVM_REQ_VCPU_RESET, target_vcpu);
373e1d8656SAtish Patra 
383e1d8656SAtish Patra 	kvm_riscv_vcpu_power_on(target_vcpu);
393e1d8656SAtish Patra 
403e1d8656SAtish Patra 	return 0;
413e1d8656SAtish Patra }
423e1d8656SAtish Patra 
433e1d8656SAtish Patra static int kvm_sbi_hsm_vcpu_stop(struct kvm_vcpu *vcpu)
443e1d8656SAtish Patra {
453e1d8656SAtish Patra 	if (vcpu->arch.power_off)
463e1d8656SAtish Patra 		return -EINVAL;
473e1d8656SAtish Patra 
483e1d8656SAtish Patra 	kvm_riscv_vcpu_power_off(vcpu);
493e1d8656SAtish Patra 
503e1d8656SAtish Patra 	return 0;
513e1d8656SAtish Patra }
523e1d8656SAtish Patra 
533e1d8656SAtish Patra static int kvm_sbi_hsm_vcpu_get_status(struct kvm_vcpu *vcpu)
543e1d8656SAtish Patra {
553e1d8656SAtish Patra 	struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
563e1d8656SAtish Patra 	unsigned long target_vcpuid = cp->a0;
573e1d8656SAtish Patra 	struct kvm_vcpu *target_vcpu;
583e1d8656SAtish Patra 
593e1d8656SAtish Patra 	target_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, target_vcpuid);
603e1d8656SAtish Patra 	if (!target_vcpu)
613e1d8656SAtish Patra 		return -EINVAL;
623e1d8656SAtish Patra 	if (!target_vcpu->arch.power_off)
63c38ff47bSAnup Patel 		return SBI_HSM_STATE_STARTED;
64*763c8bedSAnup Patel 	else if (vcpu->stat.generic.blocking)
65*763c8bedSAnup Patel 		return SBI_HSM_STATE_SUSPENDED;
663e1d8656SAtish Patra 	else
67c38ff47bSAnup Patel 		return SBI_HSM_STATE_STOPPED;
683e1d8656SAtish Patra }
693e1d8656SAtish Patra 
703e1d8656SAtish Patra static int kvm_sbi_ext_hsm_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
713e1d8656SAtish Patra 				   unsigned long *out_val,
723e1d8656SAtish Patra 				   struct kvm_cpu_trap *utrap,
733e1d8656SAtish Patra 				   bool *exit)
743e1d8656SAtish Patra {
753e1d8656SAtish Patra 	int ret = 0;
763e1d8656SAtish Patra 	struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
773e1d8656SAtish Patra 	struct kvm *kvm = vcpu->kvm;
783e1d8656SAtish Patra 	unsigned long funcid = cp->a6;
793e1d8656SAtish Patra 
803e1d8656SAtish Patra 	switch (funcid) {
813e1d8656SAtish Patra 	case SBI_EXT_HSM_HART_START:
823e1d8656SAtish Patra 		mutex_lock(&kvm->lock);
833e1d8656SAtish Patra 		ret = kvm_sbi_hsm_vcpu_start(vcpu);
843e1d8656SAtish Patra 		mutex_unlock(&kvm->lock);
853e1d8656SAtish Patra 		break;
863e1d8656SAtish Patra 	case SBI_EXT_HSM_HART_STOP:
873e1d8656SAtish Patra 		ret = kvm_sbi_hsm_vcpu_stop(vcpu);
883e1d8656SAtish Patra 		break;
893e1d8656SAtish Patra 	case SBI_EXT_HSM_HART_STATUS:
903e1d8656SAtish Patra 		ret = kvm_sbi_hsm_vcpu_get_status(vcpu);
913e1d8656SAtish Patra 		if (ret >= 0) {
923e1d8656SAtish Patra 			*out_val = ret;
933e1d8656SAtish Patra 			ret = 0;
943e1d8656SAtish Patra 		}
953e1d8656SAtish Patra 		break;
96*763c8bedSAnup Patel 	case SBI_EXT_HSM_HART_SUSPEND:
97*763c8bedSAnup Patel 		switch (cp->a0) {
98*763c8bedSAnup Patel 		case SBI_HSM_SUSPEND_RET_DEFAULT:
99*763c8bedSAnup Patel 			kvm_riscv_vcpu_wfi(vcpu);
100*763c8bedSAnup Patel 			break;
101*763c8bedSAnup Patel 		case SBI_HSM_SUSPEND_NON_RET_DEFAULT:
102*763c8bedSAnup Patel 			ret = -EOPNOTSUPP;
103*763c8bedSAnup Patel 			break;
104*763c8bedSAnup Patel 		default:
105*763c8bedSAnup Patel 			ret = -EINVAL;
106*763c8bedSAnup Patel 		}
107*763c8bedSAnup Patel 		break;
1083e1d8656SAtish Patra 	default:
1093e1d8656SAtish Patra 		ret = -EOPNOTSUPP;
1103e1d8656SAtish Patra 	}
1113e1d8656SAtish Patra 
1123e1d8656SAtish Patra 	return ret;
1133e1d8656SAtish Patra }
1143e1d8656SAtish Patra 
1153e1d8656SAtish Patra const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_hsm = {
1163e1d8656SAtish Patra 	.extid_start = SBI_EXT_HSM,
1173e1d8656SAtish Patra 	.extid_end = SBI_EXT_HSM,
1183e1d8656SAtish Patra 	.handler = kvm_sbi_ext_hsm_handler,
1193e1d8656SAtish Patra };
120