The event mapping function can be used in event info function to find out
the corresponding SBI PMU event encoding during the get_event_info function
as well. Refactor and export it so that it can be invoked from kvm and
internal driver.
Signed-off-by: Atish Patra <atishp@rivosinc.com>
---
drivers/perf/riscv_pmu_sbi.c | 124 ++++++++++++++++++++++-------------------
include/linux/perf/riscv_pmu.h | 2 +
2 files changed, 69 insertions(+), 57 deletions(-)
diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
index 33d8348bf68a..f5d3db6dba18 100644
--- a/drivers/perf/riscv_pmu_sbi.c
+++ b/drivers/perf/riscv_pmu_sbi.c
@@ -100,6 +100,7 @@ static unsigned int riscv_pmu_irq;
/* Cache the available counters in a bitmask */
static unsigned long cmask;
+static int pmu_event_find_cache(u64 config);
struct sbi_pmu_event_data {
union {
union {
@@ -411,6 +412,71 @@ static bool pmu_sbi_ctr_is_fw(int cidx)
return (info->type == SBI_PMU_CTR_TYPE_FW) ? true : false;
}
+int riscv_pmu_get_event_info(u32 type, u64 config, u64 *econfig)
+{
+ int ret = -ENOENT;
+
+ switch (type) {
+ case PERF_TYPE_HARDWARE:
+ if (config >= PERF_COUNT_HW_MAX)
+ return -EINVAL;
+ ret = pmu_hw_event_map[config].event_idx;
+ break;
+ case PERF_TYPE_HW_CACHE:
+ ret = pmu_event_find_cache(config);
+ break;
+ case PERF_TYPE_RAW:
+ /*
+ * As per SBI v0.3 specification,
+ * -- the upper 16 bits must be unused for a hardware raw event.
+ * As per SBI v3.0 specification,
+ * -- the upper 8 bits must be unused for a hardware raw event.
+ * Bits 63:62 are used to distinguish between raw events
+ * 00 - Hardware raw event
+ * 10 - SBI firmware events
+ * 11 - Risc-V platform specific firmware event
+ */
+ switch (config >> 62) {
+ case 0:
+ if (sbi_v3_available) {
+ /* Return error any bits [56-63] is set as it is not allowed by the spec */
+ if (!(config & ~RISCV_PMU_RAW_EVENT_V2_MASK)) {
+ if (econfig)
+ *econfig = config & RISCV_PMU_RAW_EVENT_V2_MASK;
+ ret = RISCV_PMU_RAW_EVENT_V2_IDX;
+ }
+ /* Return error any bits [48-63] is set as it is not allowed by the spec */
+ } else if (!(config & ~RISCV_PMU_RAW_EVENT_MASK)) {
+ if (econfig)
+ *econfig = config & RISCV_PMU_RAW_EVENT_MASK;
+ ret = RISCV_PMU_RAW_EVENT_IDX;
+ }
+ break;
+ case 2:
+ ret = (config & 0xFFFF) | (SBI_PMU_EVENT_TYPE_FW << 16);
+ break;
+ case 3:
+ /*
+ * For Risc-V platform specific firmware events
+ * Event code - 0xFFFF
+ * Event data - raw event encoding
+ */
+ ret = SBI_PMU_EVENT_TYPE_FW << 16 | RISCV_PLAT_FW_EVENT;
+ if (econfig)
+ *econfig = config & RISCV_PMU_PLAT_FW_EVENT_MASK;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(riscv_pmu_get_event_info);
+
/*
* Returns the counter width of a programmable counter and number of hardware
* counters. As we don't support heterogeneous CPUs yet, it is okay to just
@@ -576,7 +642,6 @@ static int pmu_sbi_event_map(struct perf_event *event, u64 *econfig)
{
u32 type = event->attr.type;
u64 config = event->attr.config;
- int ret = -ENOENT;
/*
* Ensure we are finished checking standard hardware events for
@@ -584,62 +649,7 @@ static int pmu_sbi_event_map(struct perf_event *event, u64 *econfig)
*/
flush_work(&check_std_events_work);
- switch (type) {
- case PERF_TYPE_HARDWARE:
- if (config >= PERF_COUNT_HW_MAX)
- return -EINVAL;
- ret = pmu_hw_event_map[event->attr.config].event_idx;
- break;
- case PERF_TYPE_HW_CACHE:
- ret = pmu_event_find_cache(config);
- break;
- case PERF_TYPE_RAW:
- /*
- * As per SBI v0.3 specification,
- * -- the upper 16 bits must be unused for a hardware raw event.
- * As per SBI v3.0 specification,
- * -- the upper 8 bits must be unused for a hardware raw event.
- * Bits 63:62 are used to distinguish between raw events
- * 00 - Hardware raw event
- * 10 - SBI firmware events
- * 11 - Risc-V platform specific firmware event
- */
-
- switch (config >> 62) {
- case 0:
- if (sbi_v3_available) {
- /* Return error any bits [56-63] is set as it is not allowed by the spec */
- if (!(config & ~RISCV_PMU_RAW_EVENT_V2_MASK)) {
- *econfig = config & RISCV_PMU_RAW_EVENT_V2_MASK;
- ret = RISCV_PMU_RAW_EVENT_V2_IDX;
- }
- /* Return error any bits [48-63] is set as it is not allowed by the spec */
- } else if (!(config & ~RISCV_PMU_RAW_EVENT_MASK)) {
- *econfig = config & RISCV_PMU_RAW_EVENT_MASK;
- ret = RISCV_PMU_RAW_EVENT_IDX;
- }
- break;
- case 2:
- ret = (config & 0xFFFF) | (SBI_PMU_EVENT_TYPE_FW << 16);
- break;
- case 3:
- /*
- * For Risc-V platform specific firmware events
- * Event code - 0xFFFF
- * Event data - raw event encoding
- */
- ret = SBI_PMU_EVENT_TYPE_FW << 16 | RISCV_PLAT_FW_EVENT;
- *econfig = config & RISCV_PMU_PLAT_FW_EVENT_MASK;
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
-
- return ret;
+ return riscv_pmu_get_event_info(type, config, econfig);
}
static void pmu_sbi_snapshot_free(struct riscv_pmu *pmu)
diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h
index 701974639ff2..4a5e3209c473 100644
--- a/include/linux/perf/riscv_pmu.h
+++ b/include/linux/perf/riscv_pmu.h
@@ -91,6 +91,8 @@ struct riscv_pmu *riscv_pmu_alloc(void);
int riscv_pmu_get_hpm_info(u32 *hw_ctr_width, u32 *num_hw_ctr);
#endif
+int riscv_pmu_get_event_info(u32 type, u64 config, u64 *econfig);
+
#endif /* CONFIG_RISCV_PMU */
#endif /* _RISCV_PMU_H */
--
2.43.0
On Fri, May 23, 2025 at 12:33 AM Atish Patra <atishp@rivosinc.com> wrote:
>
> The event mapping function can be used in event info function to find out
> the corresponding SBI PMU event encoding during the get_event_info function
> as well. Refactor and export it so that it can be invoked from kvm and
> internal driver.
>
> Signed-off-by: Atish Patra <atishp@rivosinc.com>
> ---
> drivers/perf/riscv_pmu_sbi.c | 124 ++++++++++++++++++++++-------------------
> include/linux/perf/riscv_pmu.h | 2 +
> 2 files changed, 69 insertions(+), 57 deletions(-)
>
> diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
> index 33d8348bf68a..f5d3db6dba18 100644
> --- a/drivers/perf/riscv_pmu_sbi.c
> +++ b/drivers/perf/riscv_pmu_sbi.c
> @@ -100,6 +100,7 @@ static unsigned int riscv_pmu_irq;
> /* Cache the available counters in a bitmask */
> static unsigned long cmask;
>
> +static int pmu_event_find_cache(u64 config);
> struct sbi_pmu_event_data {
> union {
> union {
> @@ -411,6 +412,71 @@ static bool pmu_sbi_ctr_is_fw(int cidx)
> return (info->type == SBI_PMU_CTR_TYPE_FW) ? true : false;
> }
>
> +int riscv_pmu_get_event_info(u32 type, u64 config, u64 *econfig)
> +{
> + int ret = -ENOENT;
> +
> + switch (type) {
> + case PERF_TYPE_HARDWARE:
> + if (config >= PERF_COUNT_HW_MAX)
> + return -EINVAL;
> + ret = pmu_hw_event_map[config].event_idx;
> + break;
> + case PERF_TYPE_HW_CACHE:
> + ret = pmu_event_find_cache(config);
> + break;
> + case PERF_TYPE_RAW:
> + /*
> + * As per SBI v0.3 specification,
> + * -- the upper 16 bits must be unused for a hardware raw event.
> + * As per SBI v3.0 specification,
> + * -- the upper 8 bits must be unused for a hardware raw event.
> + * Bits 63:62 are used to distinguish between raw events
> + * 00 - Hardware raw event
> + * 10 - SBI firmware events
> + * 11 - Risc-V platform specific firmware event
> + */
> + switch (config >> 62) {
> + case 0:
> + if (sbi_v3_available) {
> + /* Return error any bits [56-63] is set as it is not allowed by the spec */
> + if (!(config & ~RISCV_PMU_RAW_EVENT_V2_MASK)) {
> + if (econfig)
> + *econfig = config & RISCV_PMU_RAW_EVENT_V2_MASK;
> + ret = RISCV_PMU_RAW_EVENT_V2_IDX;
> + }
> + /* Return error any bits [48-63] is set as it is not allowed by the spec */
> + } else if (!(config & ~RISCV_PMU_RAW_EVENT_MASK)) {
> + if (econfig)
> + *econfig = config & RISCV_PMU_RAW_EVENT_MASK;
> + ret = RISCV_PMU_RAW_EVENT_IDX;
> + }
> + break;
> + case 2:
> + ret = (config & 0xFFFF) | (SBI_PMU_EVENT_TYPE_FW << 16);
> + break;
> + case 3:
> + /*
> + * For Risc-V platform specific firmware events
> + * Event code - 0xFFFF
> + * Event data - raw event encoding
> + */
> + ret = SBI_PMU_EVENT_TYPE_FW << 16 | RISCV_PLAT_FW_EVENT;
> + if (econfig)
> + *econfig = config & RISCV_PMU_PLAT_FW_EVENT_MASK;
> + break;
> + default:
> + break;
> + }
> + break;
> + default:
> + break;
> + }
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(riscv_pmu_get_event_info);
> +
> /*
> * Returns the counter width of a programmable counter and number of hardware
> * counters. As we don't support heterogeneous CPUs yet, it is okay to just
> @@ -576,7 +642,6 @@ static int pmu_sbi_event_map(struct perf_event *event, u64 *econfig)
> {
> u32 type = event->attr.type;
> u64 config = event->attr.config;
> - int ret = -ENOENT;
>
> /*
> * Ensure we are finished checking standard hardware events for
> @@ -584,62 +649,7 @@ static int pmu_sbi_event_map(struct perf_event *event, u64 *econfig)
> */
> flush_work(&check_std_events_work);
>
> - switch (type) {
> - case PERF_TYPE_HARDWARE:
> - if (config >= PERF_COUNT_HW_MAX)
> - return -EINVAL;
> - ret = pmu_hw_event_map[event->attr.config].event_idx;
> - break;
> - case PERF_TYPE_HW_CACHE:
> - ret = pmu_event_find_cache(config);
> - break;
> - case PERF_TYPE_RAW:
> - /*
> - * As per SBI v0.3 specification,
> - * -- the upper 16 bits must be unused for a hardware raw event.
> - * As per SBI v3.0 specification,
> - * -- the upper 8 bits must be unused for a hardware raw event.
> - * Bits 63:62 are used to distinguish between raw events
> - * 00 - Hardware raw event
> - * 10 - SBI firmware events
> - * 11 - Risc-V platform specific firmware event
> - */
> -
> - switch (config >> 62) {
> - case 0:
> - if (sbi_v3_available) {
> - /* Return error any bits [56-63] is set as it is not allowed by the spec */
> - if (!(config & ~RISCV_PMU_RAW_EVENT_V2_MASK)) {
> - *econfig = config & RISCV_PMU_RAW_EVENT_V2_MASK;
> - ret = RISCV_PMU_RAW_EVENT_V2_IDX;
> - }
> - /* Return error any bits [48-63] is set as it is not allowed by the spec */
> - } else if (!(config & ~RISCV_PMU_RAW_EVENT_MASK)) {
> - *econfig = config & RISCV_PMU_RAW_EVENT_MASK;
> - ret = RISCV_PMU_RAW_EVENT_IDX;
> - }
> - break;
> - case 2:
> - ret = (config & 0xFFFF) | (SBI_PMU_EVENT_TYPE_FW << 16);
> - break;
> - case 3:
> - /*
> - * For Risc-V platform specific firmware events
> - * Event code - 0xFFFF
> - * Event data - raw event encoding
> - */
> - ret = SBI_PMU_EVENT_TYPE_FW << 16 | RISCV_PLAT_FW_EVENT;
> - *econfig = config & RISCV_PMU_PLAT_FW_EVENT_MASK;
> - break;
> - default:
> - break;
> - }
> - break;
> - default:
> - break;
> - }
> -
> - return ret;
> + return riscv_pmu_get_event_info(type, config, econfig);
> }
>
> static void pmu_sbi_snapshot_free(struct riscv_pmu *pmu)
> diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h
> index 701974639ff2..4a5e3209c473 100644
> --- a/include/linux/perf/riscv_pmu.h
> +++ b/include/linux/perf/riscv_pmu.h
> @@ -91,6 +91,8 @@ struct riscv_pmu *riscv_pmu_alloc(void);
> int riscv_pmu_get_hpm_info(u32 *hw_ctr_width, u32 *num_hw_ctr);
> #endif
>
> +int riscv_pmu_get_event_info(u32 type, u64 config, u64 *econfig);
> +
> #endif /* CONFIG_RISCV_PMU */
We will see compile/link errors for users of riscv_pmu_get_event_info()
if CONFIG_RISCV_PMU_SBI is not defined. Am I missing anything
>
> #endif /* _RISCV_PMU_H */
>
> --
> 2.43.0
>
Regards,
Anup
© 2016 - 2025 Red Hat, Inc.