xref: /openbmc/linux/arch/riscv/kvm/vcpu_sbi_hsm.c (revision 3e1d86569c210ec64398091bd035e539f0e26e81)
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