mirror of
https://github.com/Fishwaldo/opensbi.git
synced 2025-07-23 21:38:42 +00:00
Some platforms such as hifive unmatched doesn't implement mcountinhibit csr. However, it has hardware events that can be monitored using 2 hpmcounter it has (i.e. mhpmcounter3 & mhpmcounter4). Currently, PMU extension disabled if mcountinhibit is absent. That's not really necessary as long as the supervisor OS keeps track of the delta value of the counters. Without mcountinhibit, the delta value won't be entirely accurate because the counters are freely running. However, that should be fine to produce an approximate counter value which can help performance analysis. Perf sampling won't work though as sscof extension is not present in hifive unmatched. Reviewed-by: Anup Patel <anup.patel@wdc.com> Reviewed-by: Bin Meng <bmeng.cn@gmail.com> Signed-off-by: Atish Patra <atish.patra@wdc.com>
87 lines
1.9 KiB
C
87 lines
1.9 KiB
C
/*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*
|
|
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
|
|
*
|
|
* Authors:
|
|
* Atish Patra <atish.patra@wdc.com>
|
|
*/
|
|
|
|
#include <sbi/sbi_ecall.h>
|
|
#include <sbi/sbi_ecall_interface.h>
|
|
#include <sbi/sbi_error.h>
|
|
#include <sbi/sbi_hart.h>
|
|
#include <sbi/sbi_trap.h>
|
|
#include <sbi/sbi_version.h>
|
|
#include <sbi/sbi_pmu.h>
|
|
#include <sbi/sbi_scratch.h>
|
|
#include <sbi/riscv_asm.h>
|
|
|
|
static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
|
|
const struct sbi_trap_regs *regs,
|
|
unsigned long *out_val,
|
|
struct sbi_trap_info *out_trap)
|
|
{
|
|
int ret = 0;
|
|
uint64_t temp;
|
|
|
|
switch (funcid) {
|
|
case SBI_EXT_PMU_NUM_COUNTERS:
|
|
ret = sbi_pmu_num_ctr();
|
|
if (ret >= 0) {
|
|
*out_val = ret;
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case SBI_EXT_PMU_COUNTER_GET_INFO:
|
|
ret = sbi_pmu_ctr_get_info(regs->a0, out_val);
|
|
break;
|
|
case SBI_EXT_PMU_COUNTER_CFG_MATCH:
|
|
#if __riscv_xlen == 32
|
|
temp = ((uint64_t)regs->a5 << 32) | regs->a4;
|
|
#else
|
|
temp = regs->a4;
|
|
#endif
|
|
ret = sbi_pmu_ctr_cfg_match(regs->a0, regs->a1, regs->a2,
|
|
regs->a3, temp);
|
|
if (ret >= 0) {
|
|
*out_val = ret;
|
|
ret = 0;
|
|
}
|
|
|
|
break;
|
|
case SBI_EXT_PMU_COUNTER_FW_READ:
|
|
ret = sbi_pmu_ctr_read(regs->a0, out_val);
|
|
break;
|
|
case SBI_EXT_PMU_COUNTER_START:
|
|
|
|
#if __riscv_xlen == 32
|
|
temp = ((uint64_t)regs->a4 << 32) | regs->a3;
|
|
#else
|
|
temp = regs->a3;
|
|
#endif
|
|
ret = sbi_pmu_ctr_start(regs->a0, regs->a1, regs->a2, temp);
|
|
break;
|
|
case SBI_EXT_PMU_COUNTER_STOP:
|
|
ret = sbi_pmu_ctr_stop(regs->a0, regs->a1, regs->a2);
|
|
break;
|
|
default:
|
|
ret = SBI_ENOTSUPP;
|
|
};
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int sbi_ecall_pmu_probe(unsigned long extid, unsigned long *out_val)
|
|
{
|
|
/* PMU extension is always enabled */
|
|
*out_val = 1;
|
|
return 0;
|
|
}
|
|
|
|
struct sbi_ecall_extension ecall_pmu = {
|
|
.extid_start = SBI_EXT_PMU,
|
|
.extid_end = SBI_EXT_PMU,
|
|
.handle = sbi_ecall_pmu_handler,
|
|
.probe = sbi_ecall_pmu_probe,
|
|
};
|