1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2023 Rivos Inc
6 * Atish Patra <atishp@rivosinc.com>
9 #include <linux/errno.h>
10 #include <linux/err.h>
11 #include <linux/kvm_host.h>
14 #include <asm/kvm_vcpu_sbi.h>
16 static int kvm_sbi_ext_pmu_handler(struct kvm_vcpu
*vcpu
, struct kvm_run
*run
,
17 struct kvm_vcpu_sbi_return
*retdata
)
20 struct kvm_cpu_context
*cp
= &vcpu
->arch
.guest_context
;
21 struct kvm_pmu
*kvpmu
= vcpu_to_pmu(vcpu
);
22 unsigned long funcid
= cp
->a6
;
25 if (!kvpmu
->init_done
) {
26 retdata
->err_val
= SBI_ERR_NOT_SUPPORTED
;
31 case SBI_EXT_PMU_NUM_COUNTERS
:
32 ret
= kvm_riscv_vcpu_pmu_num_ctrs(vcpu
, retdata
);
34 case SBI_EXT_PMU_COUNTER_GET_INFO
:
35 ret
= kvm_riscv_vcpu_pmu_ctr_info(vcpu
, cp
->a0
, retdata
);
37 case SBI_EXT_PMU_COUNTER_CFG_MATCH
:
38 #if defined(CONFIG_32BIT)
39 temp
= ((uint64_t)cp
->a5
<< 32) | cp
->a4
;
44 * This can fail if perf core framework fails to create an event.
45 * No need to forward the error to userspace and exit the guest.
46 * The operation can continue without profiling. Forward the
47 * appropriate SBI error to the guest.
49 ret
= kvm_riscv_vcpu_pmu_ctr_cfg_match(vcpu
, cp
->a0
, cp
->a1
,
50 cp
->a2
, cp
->a3
, temp
, retdata
);
52 case SBI_EXT_PMU_COUNTER_START
:
53 #if defined(CONFIG_32BIT)
54 temp
= ((uint64_t)cp
->a4
<< 32) | cp
->a3
;
58 ret
= kvm_riscv_vcpu_pmu_ctr_start(vcpu
, cp
->a0
, cp
->a1
, cp
->a2
,
61 case SBI_EXT_PMU_COUNTER_STOP
:
62 ret
= kvm_riscv_vcpu_pmu_ctr_stop(vcpu
, cp
->a0
, cp
->a1
, cp
->a2
, retdata
);
64 case SBI_EXT_PMU_COUNTER_FW_READ
:
65 ret
= kvm_riscv_vcpu_pmu_fw_ctr_read(vcpu
, cp
->a0
, retdata
);
67 case SBI_EXT_PMU_COUNTER_FW_READ_HI
:
68 if (IS_ENABLED(CONFIG_32BIT
))
69 ret
= kvm_riscv_vcpu_pmu_fw_ctr_read_hi(vcpu
, cp
->a0
, retdata
);
73 case SBI_EXT_PMU_SNAPSHOT_SET_SHMEM
:
74 ret
= kvm_riscv_vcpu_pmu_snapshot_set_shmem(vcpu
, cp
->a0
, cp
->a1
, cp
->a2
, retdata
);
77 retdata
->err_val
= SBI_ERR_NOT_SUPPORTED
;
83 static unsigned long kvm_sbi_ext_pmu_probe(struct kvm_vcpu
*vcpu
)
85 struct kvm_pmu
*kvpmu
= vcpu_to_pmu(vcpu
);
87 return kvpmu
->init_done
;
90 const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_pmu
= {
91 .extid_start
= SBI_EXT_PMU
,
92 .extid_end
= SBI_EXT_PMU
,
93 .handler
= kvm_sbi_ext_pmu_handler
,
94 .probe
= kvm_sbi_ext_pmu_probe
,