1*3e1d8656SAtish Patra // SPDX-License-Identifier: GPL-2.0 2*3e1d8656SAtish Patra /* 3*3e1d8656SAtish Patra * Copyright (c) 2021 Western Digital Corporation or its affiliates. 4*3e1d8656SAtish Patra * 5*3e1d8656SAtish Patra * Authors: 6*3e1d8656SAtish Patra * Atish Patra <atish.patra@wdc.com> 7*3e1d8656SAtish Patra */ 8*3e1d8656SAtish Patra 9*3e1d8656SAtish Patra #include <linux/errno.h> 10*3e1d8656SAtish Patra #include <linux/err.h> 11*3e1d8656SAtish Patra #include <linux/kvm_host.h> 12*3e1d8656SAtish Patra #include <asm/csr.h> 13*3e1d8656SAtish Patra #include <asm/sbi.h> 14*3e1d8656SAtish Patra #include <asm/kvm_vcpu_sbi.h> 15*3e1d8656SAtish Patra 16*3e1d8656SAtish Patra static int kvm_sbi_hsm_vcpu_start(struct kvm_vcpu *vcpu) 17*3e1d8656SAtish Patra { 18*3e1d8656SAtish Patra struct kvm_cpu_context *reset_cntx; 19*3e1d8656SAtish Patra struct kvm_cpu_context *cp = &vcpu->arch.guest_context; 20*3e1d8656SAtish Patra struct kvm_vcpu *target_vcpu; 21*3e1d8656SAtish Patra unsigned long target_vcpuid = cp->a0; 22*3e1d8656SAtish Patra 23*3e1d8656SAtish Patra target_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, target_vcpuid); 24*3e1d8656SAtish Patra if (!target_vcpu) 25*3e1d8656SAtish Patra return -EINVAL; 26*3e1d8656SAtish Patra if (!target_vcpu->arch.power_off) 27*3e1d8656SAtish Patra return -EALREADY; 28*3e1d8656SAtish Patra 29*3e1d8656SAtish Patra reset_cntx = &target_vcpu->arch.guest_reset_context; 30*3e1d8656SAtish Patra /* start address */ 31*3e1d8656SAtish Patra reset_cntx->sepc = cp->a1; 32*3e1d8656SAtish Patra /* target vcpu id to start */ 33*3e1d8656SAtish Patra reset_cntx->a0 = target_vcpuid; 34*3e1d8656SAtish Patra /* private data passed from kernel */ 35*3e1d8656SAtish Patra reset_cntx->a1 = cp->a2; 36*3e1d8656SAtish Patra kvm_make_request(KVM_REQ_VCPU_RESET, target_vcpu); 37*3e1d8656SAtish Patra 38*3e1d8656SAtish Patra kvm_riscv_vcpu_power_on(target_vcpu); 39*3e1d8656SAtish Patra 40*3e1d8656SAtish Patra return 0; 41*3e1d8656SAtish Patra } 42*3e1d8656SAtish Patra 43*3e1d8656SAtish Patra static int kvm_sbi_hsm_vcpu_stop(struct kvm_vcpu *vcpu) 44*3e1d8656SAtish Patra { 45*3e1d8656SAtish Patra if (vcpu->arch.power_off) 46*3e1d8656SAtish Patra return -EINVAL; 47*3e1d8656SAtish Patra 48*3e1d8656SAtish Patra kvm_riscv_vcpu_power_off(vcpu); 49*3e1d8656SAtish Patra 50*3e1d8656SAtish Patra return 0; 51*3e1d8656SAtish Patra } 52*3e1d8656SAtish Patra 53*3e1d8656SAtish Patra static int kvm_sbi_hsm_vcpu_get_status(struct kvm_vcpu *vcpu) 54*3e1d8656SAtish Patra { 55*3e1d8656SAtish Patra struct kvm_cpu_context *cp = &vcpu->arch.guest_context; 56*3e1d8656SAtish Patra unsigned long target_vcpuid = cp->a0; 57*3e1d8656SAtish Patra struct kvm_vcpu *target_vcpu; 58*3e1d8656SAtish Patra 59*3e1d8656SAtish Patra target_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, target_vcpuid); 60*3e1d8656SAtish Patra if (!target_vcpu) 61*3e1d8656SAtish Patra return -EINVAL; 62*3e1d8656SAtish Patra if (!target_vcpu->arch.power_off) 63*3e1d8656SAtish Patra return SBI_HSM_HART_STATUS_STARTED; 64*3e1d8656SAtish Patra else 65*3e1d8656SAtish Patra return SBI_HSM_HART_STATUS_STOPPED; 66*3e1d8656SAtish Patra } 67*3e1d8656SAtish Patra 68*3e1d8656SAtish Patra static int kvm_sbi_ext_hsm_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, 69*3e1d8656SAtish Patra unsigned long *out_val, 70*3e1d8656SAtish Patra struct kvm_cpu_trap *utrap, 71*3e1d8656SAtish Patra bool *exit) 72*3e1d8656SAtish Patra { 73*3e1d8656SAtish Patra int ret = 0; 74*3e1d8656SAtish Patra struct kvm_cpu_context *cp = &vcpu->arch.guest_context; 75*3e1d8656SAtish Patra struct kvm *kvm = vcpu->kvm; 76*3e1d8656SAtish Patra unsigned long funcid = cp->a6; 77*3e1d8656SAtish Patra 78*3e1d8656SAtish Patra switch (funcid) { 79*3e1d8656SAtish Patra case SBI_EXT_HSM_HART_START: 80*3e1d8656SAtish Patra mutex_lock(&kvm->lock); 81*3e1d8656SAtish Patra ret = kvm_sbi_hsm_vcpu_start(vcpu); 82*3e1d8656SAtish Patra mutex_unlock(&kvm->lock); 83*3e1d8656SAtish Patra break; 84*3e1d8656SAtish Patra case SBI_EXT_HSM_HART_STOP: 85*3e1d8656SAtish Patra ret = kvm_sbi_hsm_vcpu_stop(vcpu); 86*3e1d8656SAtish Patra break; 87*3e1d8656SAtish Patra case SBI_EXT_HSM_HART_STATUS: 88*3e1d8656SAtish Patra ret = kvm_sbi_hsm_vcpu_get_status(vcpu); 89*3e1d8656SAtish Patra if (ret >= 0) { 90*3e1d8656SAtish Patra *out_val = ret; 91*3e1d8656SAtish Patra ret = 0; 92*3e1d8656SAtish Patra } 93*3e1d8656SAtish Patra break; 94*3e1d8656SAtish Patra default: 95*3e1d8656SAtish Patra ret = -EOPNOTSUPP; 96*3e1d8656SAtish Patra } 97*3e1d8656SAtish Patra 98*3e1d8656SAtish Patra return ret; 99*3e1d8656SAtish Patra } 100*3e1d8656SAtish Patra 101*3e1d8656SAtish Patra const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_hsm = { 102*3e1d8656SAtish Patra .extid_start = SBI_EXT_HSM, 103*3e1d8656SAtish Patra .extid_end = SBI_EXT_HSM, 104*3e1d8656SAtish Patra .handler = kvm_sbi_ext_hsm_handler, 105*3e1d8656SAtish Patra }; 106