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 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 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 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 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