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