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