Commit 880fcc32 authored by Atish Patra's avatar Atish Patra Committed by Anup Patel
Browse files

drivers/perf: riscv: Export PMU event info function



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: default avatarAtish Patra <atishp@rivosinc.com>
Reviewed-by: default avatarAnup Patel <anup@brainfault.org>
Acked-by: default avatarPaul Walmsley <pjw@kernel.org>
Link: https://lore.kernel.org/r/20250909-pmu_event_info-v6-5-d8f80cacb884@rivosinc.com


Signed-off-by: default avatarAnup Patel <anup@brainfault.org>
parent adffbd06
Loading
Loading
Loading
Loading
+67 −55
Original line number Diff line number Diff line
@@ -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 {
@@ -412,6 +413,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 v2.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
@@ -577,7 +643,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
@@ -585,60 +650,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 v2.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) {
				if (!(config & ~RISCV_PMU_RAW_EVENT_V2_MASK)) {
					*econfig = config & RISCV_PMU_RAW_EVENT_V2_MASK;
					ret = RISCV_PMU_RAW_EVENT_V2_IDX;
				}
			} 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)
+1 −0
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ static inline void riscv_pmu_legacy_skip_init(void) {};
struct riscv_pmu *riscv_pmu_alloc(void);
#ifdef CONFIG_RISCV_PMU_SBI
int riscv_pmu_get_hpm_info(u32 *hw_ctr_width, u32 *num_hw_ctr);
int riscv_pmu_get_event_info(u32 type, u64 config, u64 *econfig);
#endif

#endif /* CONFIG_RISCV_PMU */