xref: /openbmc/linux/arch/riscv/kvm/vcpu_sbi_pmu.c (revision cbddc4c4)
1*cbddc4c4SAtish Patra // SPDX-License-Identifier: GPL-2.0
2*cbddc4c4SAtish Patra /*
3*cbddc4c4SAtish Patra  * Copyright (c) 2023 Rivos Inc
4*cbddc4c4SAtish Patra  *
5*cbddc4c4SAtish Patra  * Authors:
6*cbddc4c4SAtish Patra  *     Atish Patra <atishp@rivosinc.com>
7*cbddc4c4SAtish Patra  */
8*cbddc4c4SAtish Patra 
9*cbddc4c4SAtish Patra #include <linux/errno.h>
10*cbddc4c4SAtish Patra #include <linux/err.h>
11*cbddc4c4SAtish Patra #include <linux/kvm_host.h>
12*cbddc4c4SAtish Patra #include <asm/csr.h>
13*cbddc4c4SAtish Patra #include <asm/sbi.h>
14*cbddc4c4SAtish Patra #include <asm/kvm_vcpu_sbi.h>
15*cbddc4c4SAtish Patra 
kvm_sbi_ext_pmu_handler(struct kvm_vcpu * vcpu,struct kvm_run * run,struct kvm_vcpu_sbi_return * retdata)16*cbddc4c4SAtish Patra static int kvm_sbi_ext_pmu_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
17*cbddc4c4SAtish Patra 				   struct kvm_vcpu_sbi_return *retdata)
18*cbddc4c4SAtish Patra {
19*cbddc4c4SAtish Patra 	int ret = 0;
20*cbddc4c4SAtish Patra 	struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
21*cbddc4c4SAtish Patra 	struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu);
22*cbddc4c4SAtish Patra 	unsigned long funcid = cp->a6;
23*cbddc4c4SAtish Patra 	u64 temp;
24*cbddc4c4SAtish Patra 
25*cbddc4c4SAtish Patra 	if (!kvpmu->init_done) {
26*cbddc4c4SAtish Patra 		retdata->err_val = SBI_ERR_NOT_SUPPORTED;
27*cbddc4c4SAtish Patra 		return 0;
28*cbddc4c4SAtish Patra 	}
29*cbddc4c4SAtish Patra 
30*cbddc4c4SAtish Patra 	switch (funcid) {
31*cbddc4c4SAtish Patra 	case SBI_EXT_PMU_NUM_COUNTERS:
32*cbddc4c4SAtish Patra 		ret = kvm_riscv_vcpu_pmu_num_ctrs(vcpu, retdata);
33*cbddc4c4SAtish Patra 		break;
34*cbddc4c4SAtish Patra 	case SBI_EXT_PMU_COUNTER_GET_INFO:
35*cbddc4c4SAtish Patra 		ret = kvm_riscv_vcpu_pmu_ctr_info(vcpu, cp->a0, retdata);
36*cbddc4c4SAtish Patra 		break;
37*cbddc4c4SAtish Patra 	case SBI_EXT_PMU_COUNTER_CFG_MATCH:
38*cbddc4c4SAtish Patra #if defined(CONFIG_32BIT)
39*cbddc4c4SAtish Patra 		temp = ((uint64_t)cp->a5 << 32) | cp->a4;
40*cbddc4c4SAtish Patra #else
41*cbddc4c4SAtish Patra 		temp = cp->a4;
42*cbddc4c4SAtish Patra #endif
43*cbddc4c4SAtish Patra 		/*
44*cbddc4c4SAtish Patra 		 * This can fail if perf core framework fails to create an event.
45*cbddc4c4SAtish Patra 		 * Forward the error to userspace because it's an error which
46*cbddc4c4SAtish Patra 		 * happened within the host kernel. The other option would be
47*cbddc4c4SAtish Patra 		 * to convert to an SBI error and forward to the guest.
48*cbddc4c4SAtish Patra 		 */
49*cbddc4c4SAtish Patra 		ret = kvm_riscv_vcpu_pmu_ctr_cfg_match(vcpu, cp->a0, cp->a1,
50*cbddc4c4SAtish Patra 						       cp->a2, cp->a3, temp, retdata);
51*cbddc4c4SAtish Patra 		break;
52*cbddc4c4SAtish Patra 	case SBI_EXT_PMU_COUNTER_START:
53*cbddc4c4SAtish Patra #if defined(CONFIG_32BIT)
54*cbddc4c4SAtish Patra 		temp = ((uint64_t)cp->a4 << 32) | cp->a3;
55*cbddc4c4SAtish Patra #else
56*cbddc4c4SAtish Patra 		temp = cp->a3;
57*cbddc4c4SAtish Patra #endif
58*cbddc4c4SAtish Patra 		ret = kvm_riscv_vcpu_pmu_ctr_start(vcpu, cp->a0, cp->a1, cp->a2,
59*cbddc4c4SAtish Patra 						   temp, retdata);
60*cbddc4c4SAtish Patra 		break;
61*cbddc4c4SAtish Patra 	case SBI_EXT_PMU_COUNTER_STOP:
62*cbddc4c4SAtish Patra 		ret = kvm_riscv_vcpu_pmu_ctr_stop(vcpu, cp->a0, cp->a1, cp->a2, retdata);
63*cbddc4c4SAtish Patra 		break;
64*cbddc4c4SAtish Patra 	case SBI_EXT_PMU_COUNTER_FW_READ:
65*cbddc4c4SAtish Patra 		ret = kvm_riscv_vcpu_pmu_ctr_read(vcpu, cp->a0, retdata);
66*cbddc4c4SAtish Patra 		break;
67*cbddc4c4SAtish Patra 	default:
68*cbddc4c4SAtish Patra 		retdata->err_val = SBI_ERR_NOT_SUPPORTED;
69*cbddc4c4SAtish Patra 	}
70*cbddc4c4SAtish Patra 
71*cbddc4c4SAtish Patra 	return ret;
72*cbddc4c4SAtish Patra }
73*cbddc4c4SAtish Patra 
kvm_sbi_ext_pmu_probe(struct kvm_vcpu * vcpu)74*cbddc4c4SAtish Patra static unsigned long kvm_sbi_ext_pmu_probe(struct kvm_vcpu *vcpu)
75*cbddc4c4SAtish Patra {
76*cbddc4c4SAtish Patra 	struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu);
77*cbddc4c4SAtish Patra 
78*cbddc4c4SAtish Patra 	return kvpmu->init_done;
79*cbddc4c4SAtish Patra }
80*cbddc4c4SAtish Patra 
81*cbddc4c4SAtish Patra const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_pmu = {
82*cbddc4c4SAtish Patra 	.extid_start = SBI_EXT_PMU,
83*cbddc4c4SAtish Patra 	.extid_end = SBI_EXT_PMU,
84*cbddc4c4SAtish Patra 	.handler = kvm_sbi_ext_pmu_handler,
85*cbddc4c4SAtish Patra 	.probe = kvm_sbi_ext_pmu_probe,
86*cbddc4c4SAtish Patra };
87