Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drivers/perf: riscv: Implement PMU event info function

With the new SBI PMU event info function, we can query the availability
of the all standard SBI PMU events at boot time with a single ecall.
This improves the bootime by avoiding making an SBI call for each
standard PMU event. Since this function is defined only in SBI v3.0,
invoke this only if the underlying SBI implementation is v3.0 or higher.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Acked-by: Paul Walmsley <pjw@kernel.org>
Link: https://lore.kernel.org/r/20250909-pmu_event_info-v6-4-d8f80cacb884@rivosinc.com
Signed-off-by: Anup Patel <anup@brainfault.org>

authored by

Atish Patra and committed by
Anup Patel
adffbd06 190b7415

+78
+9
arch/riscv/include/asm/sbi.h
··· 136 136 SBI_EXT_PMU_COUNTER_FW_READ, 137 137 SBI_EXT_PMU_COUNTER_FW_READ_HI, 138 138 SBI_EXT_PMU_SNAPSHOT_SET_SHMEM, 139 + SBI_EXT_PMU_EVENT_GET_INFO, 139 140 }; 140 141 141 142 union sbi_pmu_ctr_info { ··· 159 158 u64 ctr_values[64]; 160 159 u64 reserved[447]; 161 160 }; 161 + 162 + struct riscv_pmu_event_info { 163 + u32 event_idx; 164 + u32 output; 165 + u64 event_data; 166 + }; 167 + 168 + #define RISCV_PMU_EVENT_INFO_OUTPUT_MASK 0x01 162 169 163 170 #define RISCV_PMU_RAW_EVENT_MASK GENMASK_ULL(47, 0) 164 171 #define RISCV_PMU_PLAT_FW_EVENT_MASK GENMASK_ULL(61, 0)
+69
drivers/perf/riscv_pmu_sbi.c
··· 299 299 }, 300 300 }; 301 301 302 + static int pmu_sbi_check_event_info(void) 303 + { 304 + int num_events = ARRAY_SIZE(pmu_hw_event_map) + PERF_COUNT_HW_CACHE_MAX * 305 + PERF_COUNT_HW_CACHE_OP_MAX * PERF_COUNT_HW_CACHE_RESULT_MAX; 306 + struct riscv_pmu_event_info *event_info_shmem; 307 + phys_addr_t base_addr; 308 + int i, j, k, result = 0, count = 0; 309 + struct sbiret ret; 310 + 311 + event_info_shmem = kcalloc(num_events, sizeof(*event_info_shmem), GFP_KERNEL); 312 + if (!event_info_shmem) 313 + return -ENOMEM; 314 + 315 + for (i = 0; i < ARRAY_SIZE(pmu_hw_event_map); i++) 316 + event_info_shmem[count++].event_idx = pmu_hw_event_map[i].event_idx; 317 + 318 + for (i = 0; i < ARRAY_SIZE(pmu_cache_event_map); i++) { 319 + for (j = 0; j < ARRAY_SIZE(pmu_cache_event_map[i]); j++) { 320 + for (k = 0; k < ARRAY_SIZE(pmu_cache_event_map[i][j]); k++) 321 + event_info_shmem[count++].event_idx = 322 + pmu_cache_event_map[i][j][k].event_idx; 323 + } 324 + } 325 + 326 + base_addr = __pa(event_info_shmem); 327 + if (IS_ENABLED(CONFIG_32BIT)) 328 + ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_EVENT_GET_INFO, lower_32_bits(base_addr), 329 + upper_32_bits(base_addr), count, 0, 0, 0); 330 + else 331 + ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_EVENT_GET_INFO, base_addr, 0, 332 + count, 0, 0, 0); 333 + if (ret.error) { 334 + result = -EOPNOTSUPP; 335 + goto free_mem; 336 + } 337 + 338 + for (i = 0; i < ARRAY_SIZE(pmu_hw_event_map); i++) { 339 + if (!(event_info_shmem[i].output & RISCV_PMU_EVENT_INFO_OUTPUT_MASK)) 340 + pmu_hw_event_map[i].event_idx = -ENOENT; 341 + } 342 + 343 + count = ARRAY_SIZE(pmu_hw_event_map); 344 + 345 + for (i = 0; i < ARRAY_SIZE(pmu_cache_event_map); i++) { 346 + for (j = 0; j < ARRAY_SIZE(pmu_cache_event_map[i]); j++) { 347 + for (k = 0; k < ARRAY_SIZE(pmu_cache_event_map[i][j]); k++) { 348 + if (!(event_info_shmem[count].output & 349 + RISCV_PMU_EVENT_INFO_OUTPUT_MASK)) 350 + pmu_cache_event_map[i][j][k].event_idx = -ENOENT; 351 + count++; 352 + } 353 + } 354 + } 355 + 356 + free_mem: 357 + kfree(event_info_shmem); 358 + 359 + return result; 360 + } 361 + 302 362 static void pmu_sbi_check_event(struct sbi_pmu_event_data *edata) 303 363 { 304 364 struct sbiret ret; ··· 376 316 377 317 static void pmu_sbi_check_std_events(struct work_struct *work) 378 318 { 319 + int ret; 320 + 321 + if (sbi_v3_available) { 322 + ret = pmu_sbi_check_event_info(); 323 + if (ret) 324 + pr_err("pmu_sbi_check_event_info failed with error %d\n", ret); 325 + return; 326 + } 327 + 379 328 for (int i = 0; i < ARRAY_SIZE(pmu_hw_event_map); i++) 380 329 pmu_sbi_check_event(&pmu_hw_event_map[i]); 381 330