17755cec6SMarc Zyngier // SPDX-License-Identifier: GPL-2.0-only 27755cec6SMarc Zyngier /* 37755cec6SMarc Zyngier * ARMv8 PMUv3 Performance Events handling code. 47755cec6SMarc Zyngier * 57755cec6SMarc Zyngier * Copyright (C) 2012 ARM Limited 67755cec6SMarc Zyngier * Author: Will Deacon <will.deacon@arm.com> 77755cec6SMarc Zyngier * 87755cec6SMarc Zyngier * This code is based heavily on the ARMv7 perf event code. 97755cec6SMarc Zyngier */ 107755cec6SMarc Zyngier 117755cec6SMarc Zyngier #include <asm/irq_regs.h> 127755cec6SMarc Zyngier #include <asm/perf_event.h> 137755cec6SMarc Zyngier #include <asm/virt.h> 147755cec6SMarc Zyngier 157755cec6SMarc Zyngier #include <clocksource/arm_arch_timer.h> 167755cec6SMarc Zyngier 177755cec6SMarc Zyngier #include <linux/acpi.h> 187755cec6SMarc Zyngier #include <linux/clocksource.h> 197755cec6SMarc Zyngier #include <linux/of.h> 207755cec6SMarc Zyngier #include <linux/perf/arm_pmu.h> 217755cec6SMarc Zyngier #include <linux/perf/arm_pmuv3.h> 227755cec6SMarc Zyngier #include <linux/platform_device.h> 237755cec6SMarc Zyngier #include <linux/sched_clock.h> 247755cec6SMarc Zyngier #include <linux/smp.h> 257755cec6SMarc Zyngier 26df29ddf4SMarc Zyngier #include <asm/arm_pmuv3.h> 27df29ddf4SMarc Zyngier 287755cec6SMarc Zyngier /* ARMv8 Cortex-A53 specific event types. */ 297755cec6SMarc Zyngier #define ARMV8_A53_PERFCTR_PREF_LINEFILL 0xC2 307755cec6SMarc Zyngier 317755cec6SMarc Zyngier /* ARMv8 Cavium ThunderX specific event types. */ 327755cec6SMarc Zyngier #define ARMV8_THUNDER_PERFCTR_L1D_CACHE_MISS_ST 0xE9 337755cec6SMarc Zyngier #define ARMV8_THUNDER_PERFCTR_L1D_CACHE_PREF_ACCESS 0xEA 347755cec6SMarc Zyngier #define ARMV8_THUNDER_PERFCTR_L1D_CACHE_PREF_MISS 0xEB 357755cec6SMarc Zyngier #define ARMV8_THUNDER_PERFCTR_L1I_CACHE_PREF_ACCESS 0xEC 367755cec6SMarc Zyngier #define ARMV8_THUNDER_PERFCTR_L1I_CACHE_PREF_MISS 0xED 377755cec6SMarc Zyngier 387755cec6SMarc Zyngier /* 397755cec6SMarc Zyngier * ARMv8 Architectural defined events, not all of these may 407755cec6SMarc Zyngier * be supported on any given implementation. Unsupported events will 417755cec6SMarc Zyngier * be disabled at run-time based on the PMCEID registers. 427755cec6SMarc Zyngier */ 437755cec6SMarc Zyngier static const unsigned armv8_pmuv3_perf_map[PERF_COUNT_HW_MAX] = { 447755cec6SMarc Zyngier PERF_MAP_ALL_UNSUPPORTED, 457755cec6SMarc Zyngier [PERF_COUNT_HW_CPU_CYCLES] = ARMV8_PMUV3_PERFCTR_CPU_CYCLES, 467755cec6SMarc Zyngier [PERF_COUNT_HW_INSTRUCTIONS] = ARMV8_PMUV3_PERFCTR_INST_RETIRED, 477755cec6SMarc Zyngier [PERF_COUNT_HW_CACHE_REFERENCES] = ARMV8_PMUV3_PERFCTR_L1D_CACHE, 487755cec6SMarc Zyngier [PERF_COUNT_HW_CACHE_MISSES] = ARMV8_PMUV3_PERFCTR_L1D_CACHE_REFILL, 497755cec6SMarc Zyngier [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV8_PMUV3_PERFCTR_PC_WRITE_RETIRED, 507755cec6SMarc Zyngier [PERF_COUNT_HW_BRANCH_MISSES] = ARMV8_PMUV3_PERFCTR_BR_MIS_PRED, 517755cec6SMarc Zyngier [PERF_COUNT_HW_BUS_CYCLES] = ARMV8_PMUV3_PERFCTR_BUS_CYCLES, 527755cec6SMarc Zyngier [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = ARMV8_PMUV3_PERFCTR_STALL_FRONTEND, 537755cec6SMarc Zyngier [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = ARMV8_PMUV3_PERFCTR_STALL_BACKEND, 547755cec6SMarc Zyngier }; 557755cec6SMarc Zyngier 567755cec6SMarc Zyngier static const unsigned armv8_pmuv3_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] 577755cec6SMarc Zyngier [PERF_COUNT_HW_CACHE_OP_MAX] 587755cec6SMarc Zyngier [PERF_COUNT_HW_CACHE_RESULT_MAX] = { 597755cec6SMarc Zyngier PERF_CACHE_MAP_ALL_UNSUPPORTED, 607755cec6SMarc Zyngier 617755cec6SMarc Zyngier [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_L1D_CACHE, 627755cec6SMarc Zyngier [C(L1D)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_L1D_CACHE_REFILL, 637755cec6SMarc Zyngier 647755cec6SMarc Zyngier [C(L1I)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_L1I_CACHE, 657755cec6SMarc Zyngier [C(L1I)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_L1I_CACHE_REFILL, 667755cec6SMarc Zyngier 677755cec6SMarc Zyngier [C(DTLB)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_L1D_TLB_REFILL, 687755cec6SMarc Zyngier [C(DTLB)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_L1D_TLB, 697755cec6SMarc Zyngier 707755cec6SMarc Zyngier [C(ITLB)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_L1I_TLB_REFILL, 717755cec6SMarc Zyngier [C(ITLB)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_L1I_TLB, 727755cec6SMarc Zyngier 737755cec6SMarc Zyngier [C(LL)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_LL_CACHE_MISS_RD, 747755cec6SMarc Zyngier [C(LL)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_LL_CACHE_RD, 757755cec6SMarc Zyngier 767755cec6SMarc Zyngier [C(BPU)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_BR_PRED, 777755cec6SMarc Zyngier [C(BPU)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_BR_MIS_PRED, 787755cec6SMarc Zyngier }; 797755cec6SMarc Zyngier 807755cec6SMarc Zyngier static const unsigned armv8_a53_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] 817755cec6SMarc Zyngier [PERF_COUNT_HW_CACHE_OP_MAX] 827755cec6SMarc Zyngier [PERF_COUNT_HW_CACHE_RESULT_MAX] = { 837755cec6SMarc Zyngier PERF_CACHE_MAP_ALL_UNSUPPORTED, 847755cec6SMarc Zyngier 857755cec6SMarc Zyngier [C(L1D)][C(OP_PREFETCH)][C(RESULT_MISS)] = ARMV8_A53_PERFCTR_PREF_LINEFILL, 867755cec6SMarc Zyngier 877755cec6SMarc Zyngier [C(NODE)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_RD, 887755cec6SMarc Zyngier [C(NODE)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_WR, 897755cec6SMarc Zyngier }; 907755cec6SMarc Zyngier 917755cec6SMarc Zyngier static const unsigned armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] 927755cec6SMarc Zyngier [PERF_COUNT_HW_CACHE_OP_MAX] 937755cec6SMarc Zyngier [PERF_COUNT_HW_CACHE_RESULT_MAX] = { 947755cec6SMarc Zyngier PERF_CACHE_MAP_ALL_UNSUPPORTED, 957755cec6SMarc Zyngier 967755cec6SMarc Zyngier [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_RD, 977755cec6SMarc Zyngier [C(L1D)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_REFILL_RD, 987755cec6SMarc Zyngier [C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_WR, 997755cec6SMarc Zyngier [C(L1D)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_REFILL_WR, 1007755cec6SMarc Zyngier 1017755cec6SMarc Zyngier [C(DTLB)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_REFILL_RD, 1027755cec6SMarc Zyngier [C(DTLB)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_REFILL_WR, 1037755cec6SMarc Zyngier 1047755cec6SMarc Zyngier [C(NODE)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_RD, 1057755cec6SMarc Zyngier [C(NODE)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_WR, 1067755cec6SMarc Zyngier }; 1077755cec6SMarc Zyngier 1087755cec6SMarc Zyngier static const unsigned armv8_a73_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] 1097755cec6SMarc Zyngier [PERF_COUNT_HW_CACHE_OP_MAX] 1107755cec6SMarc Zyngier [PERF_COUNT_HW_CACHE_RESULT_MAX] = { 1117755cec6SMarc Zyngier PERF_CACHE_MAP_ALL_UNSUPPORTED, 1127755cec6SMarc Zyngier 1137755cec6SMarc Zyngier [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_RD, 1147755cec6SMarc Zyngier [C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_WR, 1157755cec6SMarc Zyngier }; 1167755cec6SMarc Zyngier 1177755cec6SMarc Zyngier static const unsigned armv8_thunder_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] 1187755cec6SMarc Zyngier [PERF_COUNT_HW_CACHE_OP_MAX] 1197755cec6SMarc Zyngier [PERF_COUNT_HW_CACHE_RESULT_MAX] = { 1207755cec6SMarc Zyngier PERF_CACHE_MAP_ALL_UNSUPPORTED, 1217755cec6SMarc Zyngier 1227755cec6SMarc Zyngier [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_RD, 1237755cec6SMarc Zyngier [C(L1D)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_REFILL_RD, 1247755cec6SMarc Zyngier [C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_WR, 1257755cec6SMarc Zyngier [C(L1D)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_THUNDER_PERFCTR_L1D_CACHE_MISS_ST, 1267755cec6SMarc Zyngier [C(L1D)][C(OP_PREFETCH)][C(RESULT_ACCESS)] = ARMV8_THUNDER_PERFCTR_L1D_CACHE_PREF_ACCESS, 1277755cec6SMarc Zyngier [C(L1D)][C(OP_PREFETCH)][C(RESULT_MISS)] = ARMV8_THUNDER_PERFCTR_L1D_CACHE_PREF_MISS, 1287755cec6SMarc Zyngier 1297755cec6SMarc Zyngier [C(L1I)][C(OP_PREFETCH)][C(RESULT_ACCESS)] = ARMV8_THUNDER_PERFCTR_L1I_CACHE_PREF_ACCESS, 1307755cec6SMarc Zyngier [C(L1I)][C(OP_PREFETCH)][C(RESULT_MISS)] = ARMV8_THUNDER_PERFCTR_L1I_CACHE_PREF_MISS, 1317755cec6SMarc Zyngier 1327755cec6SMarc Zyngier [C(DTLB)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_RD, 1337755cec6SMarc Zyngier [C(DTLB)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_REFILL_RD, 1347755cec6SMarc Zyngier [C(DTLB)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_WR, 1357755cec6SMarc Zyngier [C(DTLB)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_REFILL_WR, 1367755cec6SMarc Zyngier }; 1377755cec6SMarc Zyngier 1387755cec6SMarc Zyngier static const unsigned armv8_vulcan_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] 1397755cec6SMarc Zyngier [PERF_COUNT_HW_CACHE_OP_MAX] 1407755cec6SMarc Zyngier [PERF_COUNT_HW_CACHE_RESULT_MAX] = { 1417755cec6SMarc Zyngier PERF_CACHE_MAP_ALL_UNSUPPORTED, 1427755cec6SMarc Zyngier 1437755cec6SMarc Zyngier [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_RD, 1447755cec6SMarc Zyngier [C(L1D)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_REFILL_RD, 1457755cec6SMarc Zyngier [C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_WR, 1467755cec6SMarc Zyngier [C(L1D)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_REFILL_WR, 1477755cec6SMarc Zyngier 1487755cec6SMarc Zyngier [C(DTLB)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_RD, 1497755cec6SMarc Zyngier [C(DTLB)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_WR, 1507755cec6SMarc Zyngier [C(DTLB)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_REFILL_RD, 1517755cec6SMarc Zyngier [C(DTLB)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_REFILL_WR, 1527755cec6SMarc Zyngier 1537755cec6SMarc Zyngier [C(NODE)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_RD, 1547755cec6SMarc Zyngier [C(NODE)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_WR, 1557755cec6SMarc Zyngier }; 1567755cec6SMarc Zyngier 1577755cec6SMarc Zyngier static ssize_t 1587755cec6SMarc Zyngier armv8pmu_events_sysfs_show(struct device *dev, 1597755cec6SMarc Zyngier struct device_attribute *attr, char *page) 1607755cec6SMarc Zyngier { 1617755cec6SMarc Zyngier struct perf_pmu_events_attr *pmu_attr; 1627755cec6SMarc Zyngier 1637755cec6SMarc Zyngier pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr); 1647755cec6SMarc Zyngier 1657755cec6SMarc Zyngier return sprintf(page, "event=0x%04llx\n", pmu_attr->id); 1667755cec6SMarc Zyngier } 1677755cec6SMarc Zyngier 1687755cec6SMarc Zyngier #define ARMV8_EVENT_ATTR(name, config) \ 1697755cec6SMarc Zyngier PMU_EVENT_ATTR_ID(name, armv8pmu_events_sysfs_show, config) 1707755cec6SMarc Zyngier 1717755cec6SMarc Zyngier static struct attribute *armv8_pmuv3_event_attrs[] = { 1727755cec6SMarc Zyngier ARMV8_EVENT_ATTR(sw_incr, ARMV8_PMUV3_PERFCTR_SW_INCR), 1737755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l1i_cache_refill, ARMV8_PMUV3_PERFCTR_L1I_CACHE_REFILL), 1747755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l1i_tlb_refill, ARMV8_PMUV3_PERFCTR_L1I_TLB_REFILL), 1757755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l1d_cache_refill, ARMV8_PMUV3_PERFCTR_L1D_CACHE_REFILL), 1767755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l1d_cache, ARMV8_PMUV3_PERFCTR_L1D_CACHE), 1777755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l1d_tlb_refill, ARMV8_PMUV3_PERFCTR_L1D_TLB_REFILL), 1787755cec6SMarc Zyngier ARMV8_EVENT_ATTR(ld_retired, ARMV8_PMUV3_PERFCTR_LD_RETIRED), 1797755cec6SMarc Zyngier ARMV8_EVENT_ATTR(st_retired, ARMV8_PMUV3_PERFCTR_ST_RETIRED), 1807755cec6SMarc Zyngier ARMV8_EVENT_ATTR(inst_retired, ARMV8_PMUV3_PERFCTR_INST_RETIRED), 1817755cec6SMarc Zyngier ARMV8_EVENT_ATTR(exc_taken, ARMV8_PMUV3_PERFCTR_EXC_TAKEN), 1827755cec6SMarc Zyngier ARMV8_EVENT_ATTR(exc_return, ARMV8_PMUV3_PERFCTR_EXC_RETURN), 1837755cec6SMarc Zyngier ARMV8_EVENT_ATTR(cid_write_retired, ARMV8_PMUV3_PERFCTR_CID_WRITE_RETIRED), 1847755cec6SMarc Zyngier ARMV8_EVENT_ATTR(pc_write_retired, ARMV8_PMUV3_PERFCTR_PC_WRITE_RETIRED), 1857755cec6SMarc Zyngier ARMV8_EVENT_ATTR(br_immed_retired, ARMV8_PMUV3_PERFCTR_BR_IMMED_RETIRED), 1867755cec6SMarc Zyngier ARMV8_EVENT_ATTR(br_return_retired, ARMV8_PMUV3_PERFCTR_BR_RETURN_RETIRED), 1877755cec6SMarc Zyngier ARMV8_EVENT_ATTR(unaligned_ldst_retired, ARMV8_PMUV3_PERFCTR_UNALIGNED_LDST_RETIRED), 1887755cec6SMarc Zyngier ARMV8_EVENT_ATTR(br_mis_pred, ARMV8_PMUV3_PERFCTR_BR_MIS_PRED), 1897755cec6SMarc Zyngier ARMV8_EVENT_ATTR(cpu_cycles, ARMV8_PMUV3_PERFCTR_CPU_CYCLES), 1907755cec6SMarc Zyngier ARMV8_EVENT_ATTR(br_pred, ARMV8_PMUV3_PERFCTR_BR_PRED), 1917755cec6SMarc Zyngier ARMV8_EVENT_ATTR(mem_access, ARMV8_PMUV3_PERFCTR_MEM_ACCESS), 1927755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l1i_cache, ARMV8_PMUV3_PERFCTR_L1I_CACHE), 1937755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l1d_cache_wb, ARMV8_PMUV3_PERFCTR_L1D_CACHE_WB), 1947755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l2d_cache, ARMV8_PMUV3_PERFCTR_L2D_CACHE), 1957755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l2d_cache_refill, ARMV8_PMUV3_PERFCTR_L2D_CACHE_REFILL), 1967755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l2d_cache_wb, ARMV8_PMUV3_PERFCTR_L2D_CACHE_WB), 1977755cec6SMarc Zyngier ARMV8_EVENT_ATTR(bus_access, ARMV8_PMUV3_PERFCTR_BUS_ACCESS), 1987755cec6SMarc Zyngier ARMV8_EVENT_ATTR(memory_error, ARMV8_PMUV3_PERFCTR_MEMORY_ERROR), 1997755cec6SMarc Zyngier ARMV8_EVENT_ATTR(inst_spec, ARMV8_PMUV3_PERFCTR_INST_SPEC), 2007755cec6SMarc Zyngier ARMV8_EVENT_ATTR(ttbr_write_retired, ARMV8_PMUV3_PERFCTR_TTBR_WRITE_RETIRED), 2017755cec6SMarc Zyngier ARMV8_EVENT_ATTR(bus_cycles, ARMV8_PMUV3_PERFCTR_BUS_CYCLES), 2027755cec6SMarc Zyngier /* Don't expose the chain event in /sys, since it's useless in isolation */ 2037755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l1d_cache_allocate, ARMV8_PMUV3_PERFCTR_L1D_CACHE_ALLOCATE), 2047755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l2d_cache_allocate, ARMV8_PMUV3_PERFCTR_L2D_CACHE_ALLOCATE), 2057755cec6SMarc Zyngier ARMV8_EVENT_ATTR(br_retired, ARMV8_PMUV3_PERFCTR_BR_RETIRED), 2067755cec6SMarc Zyngier ARMV8_EVENT_ATTR(br_mis_pred_retired, ARMV8_PMUV3_PERFCTR_BR_MIS_PRED_RETIRED), 2077755cec6SMarc Zyngier ARMV8_EVENT_ATTR(stall_frontend, ARMV8_PMUV3_PERFCTR_STALL_FRONTEND), 2087755cec6SMarc Zyngier ARMV8_EVENT_ATTR(stall_backend, ARMV8_PMUV3_PERFCTR_STALL_BACKEND), 2097755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l1d_tlb, ARMV8_PMUV3_PERFCTR_L1D_TLB), 2107755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l1i_tlb, ARMV8_PMUV3_PERFCTR_L1I_TLB), 2117755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l2i_cache, ARMV8_PMUV3_PERFCTR_L2I_CACHE), 2127755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l2i_cache_refill, ARMV8_PMUV3_PERFCTR_L2I_CACHE_REFILL), 2137755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l3d_cache_allocate, ARMV8_PMUV3_PERFCTR_L3D_CACHE_ALLOCATE), 2147755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l3d_cache_refill, ARMV8_PMUV3_PERFCTR_L3D_CACHE_REFILL), 2157755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l3d_cache, ARMV8_PMUV3_PERFCTR_L3D_CACHE), 2167755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l3d_cache_wb, ARMV8_PMUV3_PERFCTR_L3D_CACHE_WB), 2177755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l2d_tlb_refill, ARMV8_PMUV3_PERFCTR_L2D_TLB_REFILL), 2187755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l2i_tlb_refill, ARMV8_PMUV3_PERFCTR_L2I_TLB_REFILL), 2197755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l2d_tlb, ARMV8_PMUV3_PERFCTR_L2D_TLB), 2207755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l2i_tlb, ARMV8_PMUV3_PERFCTR_L2I_TLB), 2217755cec6SMarc Zyngier ARMV8_EVENT_ATTR(remote_access, ARMV8_PMUV3_PERFCTR_REMOTE_ACCESS), 2227755cec6SMarc Zyngier ARMV8_EVENT_ATTR(ll_cache, ARMV8_PMUV3_PERFCTR_LL_CACHE), 2237755cec6SMarc Zyngier ARMV8_EVENT_ATTR(ll_cache_miss, ARMV8_PMUV3_PERFCTR_LL_CACHE_MISS), 2247755cec6SMarc Zyngier ARMV8_EVENT_ATTR(dtlb_walk, ARMV8_PMUV3_PERFCTR_DTLB_WALK), 2257755cec6SMarc Zyngier ARMV8_EVENT_ATTR(itlb_walk, ARMV8_PMUV3_PERFCTR_ITLB_WALK), 2267755cec6SMarc Zyngier ARMV8_EVENT_ATTR(ll_cache_rd, ARMV8_PMUV3_PERFCTR_LL_CACHE_RD), 2277755cec6SMarc Zyngier ARMV8_EVENT_ATTR(ll_cache_miss_rd, ARMV8_PMUV3_PERFCTR_LL_CACHE_MISS_RD), 2287755cec6SMarc Zyngier ARMV8_EVENT_ATTR(remote_access_rd, ARMV8_PMUV3_PERFCTR_REMOTE_ACCESS_RD), 2297755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l1d_cache_lmiss_rd, ARMV8_PMUV3_PERFCTR_L1D_CACHE_LMISS_RD), 2307755cec6SMarc Zyngier ARMV8_EVENT_ATTR(op_retired, ARMV8_PMUV3_PERFCTR_OP_RETIRED), 2317755cec6SMarc Zyngier ARMV8_EVENT_ATTR(op_spec, ARMV8_PMUV3_PERFCTR_OP_SPEC), 2327755cec6SMarc Zyngier ARMV8_EVENT_ATTR(stall, ARMV8_PMUV3_PERFCTR_STALL), 2337755cec6SMarc Zyngier ARMV8_EVENT_ATTR(stall_slot_backend, ARMV8_PMUV3_PERFCTR_STALL_SLOT_BACKEND), 2347755cec6SMarc Zyngier ARMV8_EVENT_ATTR(stall_slot_frontend, ARMV8_PMUV3_PERFCTR_STALL_SLOT_FRONTEND), 2357755cec6SMarc Zyngier ARMV8_EVENT_ATTR(stall_slot, ARMV8_PMUV3_PERFCTR_STALL_SLOT), 2367755cec6SMarc Zyngier ARMV8_EVENT_ATTR(sample_pop, ARMV8_SPE_PERFCTR_SAMPLE_POP), 2377755cec6SMarc Zyngier ARMV8_EVENT_ATTR(sample_feed, ARMV8_SPE_PERFCTR_SAMPLE_FEED), 2387755cec6SMarc Zyngier ARMV8_EVENT_ATTR(sample_filtrate, ARMV8_SPE_PERFCTR_SAMPLE_FILTRATE), 2397755cec6SMarc Zyngier ARMV8_EVENT_ATTR(sample_collision, ARMV8_SPE_PERFCTR_SAMPLE_COLLISION), 2407755cec6SMarc Zyngier ARMV8_EVENT_ATTR(cnt_cycles, ARMV8_AMU_PERFCTR_CNT_CYCLES), 2417755cec6SMarc Zyngier ARMV8_EVENT_ATTR(stall_backend_mem, ARMV8_AMU_PERFCTR_STALL_BACKEND_MEM), 2427755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l1i_cache_lmiss, ARMV8_PMUV3_PERFCTR_L1I_CACHE_LMISS), 2437755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l2d_cache_lmiss_rd, ARMV8_PMUV3_PERFCTR_L2D_CACHE_LMISS_RD), 2447755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l2i_cache_lmiss, ARMV8_PMUV3_PERFCTR_L2I_CACHE_LMISS), 2457755cec6SMarc Zyngier ARMV8_EVENT_ATTR(l3d_cache_lmiss_rd, ARMV8_PMUV3_PERFCTR_L3D_CACHE_LMISS_RD), 2467755cec6SMarc Zyngier ARMV8_EVENT_ATTR(trb_wrap, ARMV8_PMUV3_PERFCTR_TRB_WRAP), 2477755cec6SMarc Zyngier ARMV8_EVENT_ATTR(trb_trig, ARMV8_PMUV3_PERFCTR_TRB_TRIG), 2487755cec6SMarc Zyngier ARMV8_EVENT_ATTR(trcextout0, ARMV8_PMUV3_PERFCTR_TRCEXTOUT0), 2497755cec6SMarc Zyngier ARMV8_EVENT_ATTR(trcextout1, ARMV8_PMUV3_PERFCTR_TRCEXTOUT1), 2507755cec6SMarc Zyngier ARMV8_EVENT_ATTR(trcextout2, ARMV8_PMUV3_PERFCTR_TRCEXTOUT2), 2517755cec6SMarc Zyngier ARMV8_EVENT_ATTR(trcextout3, ARMV8_PMUV3_PERFCTR_TRCEXTOUT3), 2527755cec6SMarc Zyngier ARMV8_EVENT_ATTR(cti_trigout4, ARMV8_PMUV3_PERFCTR_CTI_TRIGOUT4), 2537755cec6SMarc Zyngier ARMV8_EVENT_ATTR(cti_trigout5, ARMV8_PMUV3_PERFCTR_CTI_TRIGOUT5), 2547755cec6SMarc Zyngier ARMV8_EVENT_ATTR(cti_trigout6, ARMV8_PMUV3_PERFCTR_CTI_TRIGOUT6), 2557755cec6SMarc Zyngier ARMV8_EVENT_ATTR(cti_trigout7, ARMV8_PMUV3_PERFCTR_CTI_TRIGOUT7), 2567755cec6SMarc Zyngier ARMV8_EVENT_ATTR(ldst_align_lat, ARMV8_PMUV3_PERFCTR_LDST_ALIGN_LAT), 2577755cec6SMarc Zyngier ARMV8_EVENT_ATTR(ld_align_lat, ARMV8_PMUV3_PERFCTR_LD_ALIGN_LAT), 2587755cec6SMarc Zyngier ARMV8_EVENT_ATTR(st_align_lat, ARMV8_PMUV3_PERFCTR_ST_ALIGN_LAT), 2597755cec6SMarc Zyngier ARMV8_EVENT_ATTR(mem_access_checked, ARMV8_MTE_PERFCTR_MEM_ACCESS_CHECKED), 2607755cec6SMarc Zyngier ARMV8_EVENT_ATTR(mem_access_checked_rd, ARMV8_MTE_PERFCTR_MEM_ACCESS_CHECKED_RD), 2617755cec6SMarc Zyngier ARMV8_EVENT_ATTR(mem_access_checked_wr, ARMV8_MTE_PERFCTR_MEM_ACCESS_CHECKED_WR), 2627755cec6SMarc Zyngier NULL, 2637755cec6SMarc Zyngier }; 2647755cec6SMarc Zyngier 2657755cec6SMarc Zyngier static umode_t 2667755cec6SMarc Zyngier armv8pmu_event_attr_is_visible(struct kobject *kobj, 2677755cec6SMarc Zyngier struct attribute *attr, int unused) 2687755cec6SMarc Zyngier { 2697755cec6SMarc Zyngier struct device *dev = kobj_to_dev(kobj); 2707755cec6SMarc Zyngier struct pmu *pmu = dev_get_drvdata(dev); 2717755cec6SMarc Zyngier struct arm_pmu *cpu_pmu = container_of(pmu, struct arm_pmu, pmu); 2727755cec6SMarc Zyngier struct perf_pmu_events_attr *pmu_attr; 2737755cec6SMarc Zyngier 2747755cec6SMarc Zyngier pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr.attr); 2757755cec6SMarc Zyngier 2767755cec6SMarc Zyngier if (pmu_attr->id < ARMV8_PMUV3_MAX_COMMON_EVENTS && 2777755cec6SMarc Zyngier test_bit(pmu_attr->id, cpu_pmu->pmceid_bitmap)) 2787755cec6SMarc Zyngier return attr->mode; 2797755cec6SMarc Zyngier 2807755cec6SMarc Zyngier if (pmu_attr->id >= ARMV8_PMUV3_EXT_COMMON_EVENT_BASE) { 2817755cec6SMarc Zyngier u64 id = pmu_attr->id - ARMV8_PMUV3_EXT_COMMON_EVENT_BASE; 2827755cec6SMarc Zyngier 2837755cec6SMarc Zyngier if (id < ARMV8_PMUV3_MAX_COMMON_EVENTS && 2847755cec6SMarc Zyngier test_bit(id, cpu_pmu->pmceid_ext_bitmap)) 2857755cec6SMarc Zyngier return attr->mode; 2867755cec6SMarc Zyngier } 2877755cec6SMarc Zyngier 2887755cec6SMarc Zyngier return 0; 2897755cec6SMarc Zyngier } 2907755cec6SMarc Zyngier 2917755cec6SMarc Zyngier static const struct attribute_group armv8_pmuv3_events_attr_group = { 2927755cec6SMarc Zyngier .name = "events", 2937755cec6SMarc Zyngier .attrs = armv8_pmuv3_event_attrs, 2947755cec6SMarc Zyngier .is_visible = armv8pmu_event_attr_is_visible, 2957755cec6SMarc Zyngier }; 2967755cec6SMarc Zyngier 2977755cec6SMarc Zyngier PMU_FORMAT_ATTR(event, "config:0-15"); 2987755cec6SMarc Zyngier PMU_FORMAT_ATTR(long, "config1:0"); 2997755cec6SMarc Zyngier PMU_FORMAT_ATTR(rdpmc, "config1:1"); 3007755cec6SMarc Zyngier 3017755cec6SMarc Zyngier static int sysctl_perf_user_access __read_mostly; 3027755cec6SMarc Zyngier 3037755cec6SMarc Zyngier static inline bool armv8pmu_event_is_64bit(struct perf_event *event) 3047755cec6SMarc Zyngier { 3057755cec6SMarc Zyngier return event->attr.config1 & 0x1; 3067755cec6SMarc Zyngier } 3077755cec6SMarc Zyngier 3087755cec6SMarc Zyngier static inline bool armv8pmu_event_want_user_access(struct perf_event *event) 3097755cec6SMarc Zyngier { 3107755cec6SMarc Zyngier return event->attr.config1 & 0x2; 3117755cec6SMarc Zyngier } 3127755cec6SMarc Zyngier 3137755cec6SMarc Zyngier static struct attribute *armv8_pmuv3_format_attrs[] = { 3147755cec6SMarc Zyngier &format_attr_event.attr, 3157755cec6SMarc Zyngier &format_attr_long.attr, 3167755cec6SMarc Zyngier &format_attr_rdpmc.attr, 3177755cec6SMarc Zyngier NULL, 3187755cec6SMarc Zyngier }; 3197755cec6SMarc Zyngier 3207755cec6SMarc Zyngier static const struct attribute_group armv8_pmuv3_format_attr_group = { 3217755cec6SMarc Zyngier .name = "format", 3227755cec6SMarc Zyngier .attrs = armv8_pmuv3_format_attrs, 3237755cec6SMarc Zyngier }; 3247755cec6SMarc Zyngier 3257755cec6SMarc Zyngier static ssize_t slots_show(struct device *dev, struct device_attribute *attr, 3267755cec6SMarc Zyngier char *page) 3277755cec6SMarc Zyngier { 3287755cec6SMarc Zyngier struct pmu *pmu = dev_get_drvdata(dev); 3297755cec6SMarc Zyngier struct arm_pmu *cpu_pmu = container_of(pmu, struct arm_pmu, pmu); 3307755cec6SMarc Zyngier u32 slots = cpu_pmu->reg_pmmir & ARMV8_PMU_SLOTS_MASK; 3317755cec6SMarc Zyngier 3327755cec6SMarc Zyngier return sysfs_emit(page, "0x%08x\n", slots); 3337755cec6SMarc Zyngier } 3347755cec6SMarc Zyngier 3357755cec6SMarc Zyngier static DEVICE_ATTR_RO(slots); 3367755cec6SMarc Zyngier 3377755cec6SMarc Zyngier static ssize_t bus_slots_show(struct device *dev, struct device_attribute *attr, 3387755cec6SMarc Zyngier char *page) 3397755cec6SMarc Zyngier { 3407755cec6SMarc Zyngier struct pmu *pmu = dev_get_drvdata(dev); 3417755cec6SMarc Zyngier struct arm_pmu *cpu_pmu = container_of(pmu, struct arm_pmu, pmu); 3427755cec6SMarc Zyngier u32 bus_slots = (cpu_pmu->reg_pmmir >> ARMV8_PMU_BUS_SLOTS_SHIFT) 3437755cec6SMarc Zyngier & ARMV8_PMU_BUS_SLOTS_MASK; 3447755cec6SMarc Zyngier 3457755cec6SMarc Zyngier return sysfs_emit(page, "0x%08x\n", bus_slots); 3467755cec6SMarc Zyngier } 3477755cec6SMarc Zyngier 3487755cec6SMarc Zyngier static DEVICE_ATTR_RO(bus_slots); 3497755cec6SMarc Zyngier 3507755cec6SMarc Zyngier static ssize_t bus_width_show(struct device *dev, struct device_attribute *attr, 3517755cec6SMarc Zyngier char *page) 3527755cec6SMarc Zyngier { 3537755cec6SMarc Zyngier struct pmu *pmu = dev_get_drvdata(dev); 3547755cec6SMarc Zyngier struct arm_pmu *cpu_pmu = container_of(pmu, struct arm_pmu, pmu); 3557755cec6SMarc Zyngier u32 bus_width = (cpu_pmu->reg_pmmir >> ARMV8_PMU_BUS_WIDTH_SHIFT) 3567755cec6SMarc Zyngier & ARMV8_PMU_BUS_WIDTH_MASK; 3577755cec6SMarc Zyngier u32 val = 0; 3587755cec6SMarc Zyngier 3597755cec6SMarc Zyngier /* Encoded as Log2(number of bytes), plus one */ 3607755cec6SMarc Zyngier if (bus_width > 2 && bus_width < 13) 3617755cec6SMarc Zyngier val = 1 << (bus_width - 1); 3627755cec6SMarc Zyngier 3637755cec6SMarc Zyngier return sysfs_emit(page, "0x%08x\n", val); 3647755cec6SMarc Zyngier } 3657755cec6SMarc Zyngier 3667755cec6SMarc Zyngier static DEVICE_ATTR_RO(bus_width); 3677755cec6SMarc Zyngier 3687755cec6SMarc Zyngier static struct attribute *armv8_pmuv3_caps_attrs[] = { 3697755cec6SMarc Zyngier &dev_attr_slots.attr, 3707755cec6SMarc Zyngier &dev_attr_bus_slots.attr, 3717755cec6SMarc Zyngier &dev_attr_bus_width.attr, 3727755cec6SMarc Zyngier NULL, 3737755cec6SMarc Zyngier }; 3747755cec6SMarc Zyngier 3757755cec6SMarc Zyngier static const struct attribute_group armv8_pmuv3_caps_attr_group = { 3767755cec6SMarc Zyngier .name = "caps", 3777755cec6SMarc Zyngier .attrs = armv8_pmuv3_caps_attrs, 3787755cec6SMarc Zyngier }; 3797755cec6SMarc Zyngier 3807755cec6SMarc Zyngier /* 3817755cec6SMarc Zyngier * Perf Events' indices 3827755cec6SMarc Zyngier */ 3837755cec6SMarc Zyngier #define ARMV8_IDX_CYCLE_COUNTER 0 3847755cec6SMarc Zyngier #define ARMV8_IDX_COUNTER0 1 3857755cec6SMarc Zyngier #define ARMV8_IDX_CYCLE_COUNTER_USER 32 3867755cec6SMarc Zyngier 3877755cec6SMarc Zyngier /* 3887755cec6SMarc Zyngier * We unconditionally enable ARMv8.5-PMU long event counter support 3897755cec6SMarc Zyngier * (64-bit events) where supported. Indicate if this arm_pmu has long 3907755cec6SMarc Zyngier * event counter support. 391*009d6dc8SMarc Zyngier * 392*009d6dc8SMarc Zyngier * On AArch32, long counters make no sense (you can't access the top 393*009d6dc8SMarc Zyngier * bits), so we only enable this on AArch64. 3947755cec6SMarc Zyngier */ 3957755cec6SMarc Zyngier static bool armv8pmu_has_long_event(struct arm_pmu *cpu_pmu) 3967755cec6SMarc Zyngier { 397*009d6dc8SMarc Zyngier return (IS_ENABLED(CONFIG_ARM64) && is_pmuv3p5(cpu_pmu->pmuver)); 3987755cec6SMarc Zyngier } 3997755cec6SMarc Zyngier 4007755cec6SMarc Zyngier static inline bool armv8pmu_event_has_user_read(struct perf_event *event) 4017755cec6SMarc Zyngier { 4027755cec6SMarc Zyngier return event->hw.flags & PERF_EVENT_FLAG_USER_READ_CNT; 4037755cec6SMarc Zyngier } 4047755cec6SMarc Zyngier 4057755cec6SMarc Zyngier /* 4067755cec6SMarc Zyngier * We must chain two programmable counters for 64 bit events, 4077755cec6SMarc Zyngier * except when we have allocated the 64bit cycle counter (for CPU 4087755cec6SMarc Zyngier * cycles event) or when user space counter access is enabled. 4097755cec6SMarc Zyngier */ 4107755cec6SMarc Zyngier static inline bool armv8pmu_event_is_chained(struct perf_event *event) 4117755cec6SMarc Zyngier { 4127755cec6SMarc Zyngier int idx = event->hw.idx; 4137755cec6SMarc Zyngier struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); 4147755cec6SMarc Zyngier 4157755cec6SMarc Zyngier return !armv8pmu_event_has_user_read(event) && 4167755cec6SMarc Zyngier armv8pmu_event_is_64bit(event) && 4177755cec6SMarc Zyngier !armv8pmu_has_long_event(cpu_pmu) && 4187755cec6SMarc Zyngier (idx != ARMV8_IDX_CYCLE_COUNTER); 4197755cec6SMarc Zyngier } 4207755cec6SMarc Zyngier 4217755cec6SMarc Zyngier /* 4227755cec6SMarc Zyngier * ARMv8 low level PMU access 4237755cec6SMarc Zyngier */ 4247755cec6SMarc Zyngier 4257755cec6SMarc Zyngier /* 4267755cec6SMarc Zyngier * Perf Event to low level counters mapping 4277755cec6SMarc Zyngier */ 4287755cec6SMarc Zyngier #define ARMV8_IDX_TO_COUNTER(x) \ 4297755cec6SMarc Zyngier (((x) - ARMV8_IDX_COUNTER0) & ARMV8_PMU_COUNTER_MASK) 4307755cec6SMarc Zyngier 4317755cec6SMarc Zyngier static inline u32 armv8pmu_pmcr_read(void) 4327755cec6SMarc Zyngier { 433df29ddf4SMarc Zyngier return read_pmcr(); 4347755cec6SMarc Zyngier } 4357755cec6SMarc Zyngier 4367755cec6SMarc Zyngier static inline void armv8pmu_pmcr_write(u32 val) 4377755cec6SMarc Zyngier { 4387755cec6SMarc Zyngier val &= ARMV8_PMU_PMCR_MASK; 4397755cec6SMarc Zyngier isb(); 440df29ddf4SMarc Zyngier write_pmcr(val); 4417755cec6SMarc Zyngier } 4427755cec6SMarc Zyngier 4437755cec6SMarc Zyngier static inline int armv8pmu_has_overflowed(u32 pmovsr) 4447755cec6SMarc Zyngier { 4457755cec6SMarc Zyngier return pmovsr & ARMV8_PMU_OVERFLOWED_MASK; 4467755cec6SMarc Zyngier } 4477755cec6SMarc Zyngier 4487755cec6SMarc Zyngier static inline int armv8pmu_counter_has_overflowed(u32 pmnc, int idx) 4497755cec6SMarc Zyngier { 4507755cec6SMarc Zyngier return pmnc & BIT(ARMV8_IDX_TO_COUNTER(idx)); 4517755cec6SMarc Zyngier } 4527755cec6SMarc Zyngier 4537755cec6SMarc Zyngier static inline u64 armv8pmu_read_evcntr(int idx) 4547755cec6SMarc Zyngier { 4557755cec6SMarc Zyngier u32 counter = ARMV8_IDX_TO_COUNTER(idx); 4567755cec6SMarc Zyngier 4577755cec6SMarc Zyngier return read_pmevcntrn(counter); 4587755cec6SMarc Zyngier } 4597755cec6SMarc Zyngier 4607755cec6SMarc Zyngier static inline u64 armv8pmu_read_hw_counter(struct perf_event *event) 4617755cec6SMarc Zyngier { 4627755cec6SMarc Zyngier int idx = event->hw.idx; 4637755cec6SMarc Zyngier u64 val = armv8pmu_read_evcntr(idx); 4647755cec6SMarc Zyngier 4657755cec6SMarc Zyngier if (armv8pmu_event_is_chained(event)) 4667755cec6SMarc Zyngier val = (val << 32) | armv8pmu_read_evcntr(idx - 1); 4677755cec6SMarc Zyngier return val; 4687755cec6SMarc Zyngier } 4697755cec6SMarc Zyngier 4707755cec6SMarc Zyngier /* 4717755cec6SMarc Zyngier * The cycle counter is always a 64-bit counter. When ARMV8_PMU_PMCR_LP 4727755cec6SMarc Zyngier * is set the event counters also become 64-bit counters. Unless the 4737755cec6SMarc Zyngier * user has requested a long counter (attr.config1) then we want to 4747755cec6SMarc Zyngier * interrupt upon 32-bit overflow - we achieve this by applying a bias. 4757755cec6SMarc Zyngier */ 4767755cec6SMarc Zyngier static bool armv8pmu_event_needs_bias(struct perf_event *event) 4777755cec6SMarc Zyngier { 4787755cec6SMarc Zyngier struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); 4797755cec6SMarc Zyngier struct hw_perf_event *hwc = &event->hw; 4807755cec6SMarc Zyngier int idx = hwc->idx; 4817755cec6SMarc Zyngier 4827755cec6SMarc Zyngier if (armv8pmu_event_is_64bit(event)) 4837755cec6SMarc Zyngier return false; 4847755cec6SMarc Zyngier 4857755cec6SMarc Zyngier if (armv8pmu_has_long_event(cpu_pmu) || 4867755cec6SMarc Zyngier idx == ARMV8_IDX_CYCLE_COUNTER) 4877755cec6SMarc Zyngier return true; 4887755cec6SMarc Zyngier 4897755cec6SMarc Zyngier return false; 4907755cec6SMarc Zyngier } 4917755cec6SMarc Zyngier 4927755cec6SMarc Zyngier static u64 armv8pmu_bias_long_counter(struct perf_event *event, u64 value) 4937755cec6SMarc Zyngier { 4947755cec6SMarc Zyngier if (armv8pmu_event_needs_bias(event)) 495b3a07086SZaid Al-Bassam value |= GENMASK_ULL(63, 32); 4967755cec6SMarc Zyngier 4977755cec6SMarc Zyngier return value; 4987755cec6SMarc Zyngier } 4997755cec6SMarc Zyngier 5007755cec6SMarc Zyngier static u64 armv8pmu_unbias_long_counter(struct perf_event *event, u64 value) 5017755cec6SMarc Zyngier { 5027755cec6SMarc Zyngier if (armv8pmu_event_needs_bias(event)) 503b3a07086SZaid Al-Bassam value &= ~GENMASK_ULL(63, 32); 5047755cec6SMarc Zyngier 5057755cec6SMarc Zyngier return value; 5067755cec6SMarc Zyngier } 5077755cec6SMarc Zyngier 5087755cec6SMarc Zyngier static u64 armv8pmu_read_counter(struct perf_event *event) 5097755cec6SMarc Zyngier { 5107755cec6SMarc Zyngier struct hw_perf_event *hwc = &event->hw; 5117755cec6SMarc Zyngier int idx = hwc->idx; 5127755cec6SMarc Zyngier u64 value; 5137755cec6SMarc Zyngier 5147755cec6SMarc Zyngier if (idx == ARMV8_IDX_CYCLE_COUNTER) 515df29ddf4SMarc Zyngier value = read_pmccntr(); 5167755cec6SMarc Zyngier else 5177755cec6SMarc Zyngier value = armv8pmu_read_hw_counter(event); 5187755cec6SMarc Zyngier 5197755cec6SMarc Zyngier return armv8pmu_unbias_long_counter(event, value); 5207755cec6SMarc Zyngier } 5217755cec6SMarc Zyngier 5227755cec6SMarc Zyngier static inline void armv8pmu_write_evcntr(int idx, u64 value) 5237755cec6SMarc Zyngier { 5247755cec6SMarc Zyngier u32 counter = ARMV8_IDX_TO_COUNTER(idx); 5257755cec6SMarc Zyngier 5267755cec6SMarc Zyngier write_pmevcntrn(counter, value); 5277755cec6SMarc Zyngier } 5287755cec6SMarc Zyngier 5297755cec6SMarc Zyngier static inline void armv8pmu_write_hw_counter(struct perf_event *event, 5307755cec6SMarc Zyngier u64 value) 5317755cec6SMarc Zyngier { 5327755cec6SMarc Zyngier int idx = event->hw.idx; 5337755cec6SMarc Zyngier 5347755cec6SMarc Zyngier if (armv8pmu_event_is_chained(event)) { 5357755cec6SMarc Zyngier armv8pmu_write_evcntr(idx, upper_32_bits(value)); 5367755cec6SMarc Zyngier armv8pmu_write_evcntr(idx - 1, lower_32_bits(value)); 5377755cec6SMarc Zyngier } else { 5387755cec6SMarc Zyngier armv8pmu_write_evcntr(idx, value); 5397755cec6SMarc Zyngier } 5407755cec6SMarc Zyngier } 5417755cec6SMarc Zyngier 5427755cec6SMarc Zyngier static void armv8pmu_write_counter(struct perf_event *event, u64 value) 5437755cec6SMarc Zyngier { 5447755cec6SMarc Zyngier struct hw_perf_event *hwc = &event->hw; 5457755cec6SMarc Zyngier int idx = hwc->idx; 5467755cec6SMarc Zyngier 5477755cec6SMarc Zyngier value = armv8pmu_bias_long_counter(event, value); 5487755cec6SMarc Zyngier 5497755cec6SMarc Zyngier if (idx == ARMV8_IDX_CYCLE_COUNTER) 550df29ddf4SMarc Zyngier write_pmccntr(value); 5517755cec6SMarc Zyngier else 5527755cec6SMarc Zyngier armv8pmu_write_hw_counter(event, value); 5537755cec6SMarc Zyngier } 5547755cec6SMarc Zyngier 5557755cec6SMarc Zyngier static inline void armv8pmu_write_evtype(int idx, u32 val) 5567755cec6SMarc Zyngier { 5577755cec6SMarc Zyngier u32 counter = ARMV8_IDX_TO_COUNTER(idx); 5587755cec6SMarc Zyngier 5597755cec6SMarc Zyngier val &= ARMV8_PMU_EVTYPE_MASK; 5607755cec6SMarc Zyngier write_pmevtypern(counter, val); 5617755cec6SMarc Zyngier } 5627755cec6SMarc Zyngier 5637755cec6SMarc Zyngier static inline void armv8pmu_write_event_type(struct perf_event *event) 5647755cec6SMarc Zyngier { 5657755cec6SMarc Zyngier struct hw_perf_event *hwc = &event->hw; 5667755cec6SMarc Zyngier int idx = hwc->idx; 5677755cec6SMarc Zyngier 5687755cec6SMarc Zyngier /* 5697755cec6SMarc Zyngier * For chained events, the low counter is programmed to count 5707755cec6SMarc Zyngier * the event of interest and the high counter is programmed 5717755cec6SMarc Zyngier * with CHAIN event code with filters set to count at all ELs. 5727755cec6SMarc Zyngier */ 5737755cec6SMarc Zyngier if (armv8pmu_event_is_chained(event)) { 5747755cec6SMarc Zyngier u32 chain_evt = ARMV8_PMUV3_PERFCTR_CHAIN | 5757755cec6SMarc Zyngier ARMV8_PMU_INCLUDE_EL2; 5767755cec6SMarc Zyngier 5777755cec6SMarc Zyngier armv8pmu_write_evtype(idx - 1, hwc->config_base); 5787755cec6SMarc Zyngier armv8pmu_write_evtype(idx, chain_evt); 5797755cec6SMarc Zyngier } else { 5807755cec6SMarc Zyngier if (idx == ARMV8_IDX_CYCLE_COUNTER) 581df29ddf4SMarc Zyngier write_pmccfiltr(hwc->config_base); 5827755cec6SMarc Zyngier else 5837755cec6SMarc Zyngier armv8pmu_write_evtype(idx, hwc->config_base); 5847755cec6SMarc Zyngier } 5857755cec6SMarc Zyngier } 5867755cec6SMarc Zyngier 5877755cec6SMarc Zyngier static u32 armv8pmu_event_cnten_mask(struct perf_event *event) 5887755cec6SMarc Zyngier { 5897755cec6SMarc Zyngier int counter = ARMV8_IDX_TO_COUNTER(event->hw.idx); 5907755cec6SMarc Zyngier u32 mask = BIT(counter); 5917755cec6SMarc Zyngier 5927755cec6SMarc Zyngier if (armv8pmu_event_is_chained(event)) 5937755cec6SMarc Zyngier mask |= BIT(counter - 1); 5947755cec6SMarc Zyngier return mask; 5957755cec6SMarc Zyngier } 5967755cec6SMarc Zyngier 5977755cec6SMarc Zyngier static inline void armv8pmu_enable_counter(u32 mask) 5987755cec6SMarc Zyngier { 5997755cec6SMarc Zyngier /* 6007755cec6SMarc Zyngier * Make sure event configuration register writes are visible before we 6017755cec6SMarc Zyngier * enable the counter. 6027755cec6SMarc Zyngier * */ 6037755cec6SMarc Zyngier isb(); 604df29ddf4SMarc Zyngier write_pmcntenset(mask); 6057755cec6SMarc Zyngier } 6067755cec6SMarc Zyngier 6077755cec6SMarc Zyngier static inline void armv8pmu_enable_event_counter(struct perf_event *event) 6087755cec6SMarc Zyngier { 6097755cec6SMarc Zyngier struct perf_event_attr *attr = &event->attr; 6107755cec6SMarc Zyngier u32 mask = armv8pmu_event_cnten_mask(event); 6117755cec6SMarc Zyngier 6127755cec6SMarc Zyngier kvm_set_pmu_events(mask, attr); 6137755cec6SMarc Zyngier 6147755cec6SMarc Zyngier /* We rely on the hypervisor switch code to enable guest counters */ 6157755cec6SMarc Zyngier if (!kvm_pmu_counter_deferred(attr)) 6167755cec6SMarc Zyngier armv8pmu_enable_counter(mask); 6177755cec6SMarc Zyngier } 6187755cec6SMarc Zyngier 6197755cec6SMarc Zyngier static inline void armv8pmu_disable_counter(u32 mask) 6207755cec6SMarc Zyngier { 621df29ddf4SMarc Zyngier write_pmcntenclr(mask); 6227755cec6SMarc Zyngier /* 6237755cec6SMarc Zyngier * Make sure the effects of disabling the counter are visible before we 6247755cec6SMarc Zyngier * start configuring the event. 6257755cec6SMarc Zyngier */ 6267755cec6SMarc Zyngier isb(); 6277755cec6SMarc Zyngier } 6287755cec6SMarc Zyngier 6297755cec6SMarc Zyngier static inline void armv8pmu_disable_event_counter(struct perf_event *event) 6307755cec6SMarc Zyngier { 6317755cec6SMarc Zyngier struct perf_event_attr *attr = &event->attr; 6327755cec6SMarc Zyngier u32 mask = armv8pmu_event_cnten_mask(event); 6337755cec6SMarc Zyngier 6347755cec6SMarc Zyngier kvm_clr_pmu_events(mask); 6357755cec6SMarc Zyngier 6367755cec6SMarc Zyngier /* We rely on the hypervisor switch code to disable guest counters */ 6377755cec6SMarc Zyngier if (!kvm_pmu_counter_deferred(attr)) 6387755cec6SMarc Zyngier armv8pmu_disable_counter(mask); 6397755cec6SMarc Zyngier } 6407755cec6SMarc Zyngier 6417755cec6SMarc Zyngier static inline void armv8pmu_enable_intens(u32 mask) 6427755cec6SMarc Zyngier { 643df29ddf4SMarc Zyngier write_pmintenset(mask); 6447755cec6SMarc Zyngier } 6457755cec6SMarc Zyngier 6467755cec6SMarc Zyngier static inline void armv8pmu_enable_event_irq(struct perf_event *event) 6477755cec6SMarc Zyngier { 6487755cec6SMarc Zyngier u32 counter = ARMV8_IDX_TO_COUNTER(event->hw.idx); 6497755cec6SMarc Zyngier armv8pmu_enable_intens(BIT(counter)); 6507755cec6SMarc Zyngier } 6517755cec6SMarc Zyngier 6527755cec6SMarc Zyngier static inline void armv8pmu_disable_intens(u32 mask) 6537755cec6SMarc Zyngier { 654df29ddf4SMarc Zyngier write_pmintenclr(mask); 6557755cec6SMarc Zyngier isb(); 6567755cec6SMarc Zyngier /* Clear the overflow flag in case an interrupt is pending. */ 657df29ddf4SMarc Zyngier write_pmovsclr(mask); 6587755cec6SMarc Zyngier isb(); 6597755cec6SMarc Zyngier } 6607755cec6SMarc Zyngier 6617755cec6SMarc Zyngier static inline void armv8pmu_disable_event_irq(struct perf_event *event) 6627755cec6SMarc Zyngier { 6637755cec6SMarc Zyngier u32 counter = ARMV8_IDX_TO_COUNTER(event->hw.idx); 6647755cec6SMarc Zyngier armv8pmu_disable_intens(BIT(counter)); 6657755cec6SMarc Zyngier } 6667755cec6SMarc Zyngier 6677755cec6SMarc Zyngier static inline u32 armv8pmu_getreset_flags(void) 6687755cec6SMarc Zyngier { 6697755cec6SMarc Zyngier u32 value; 6707755cec6SMarc Zyngier 6717755cec6SMarc Zyngier /* Read */ 672df29ddf4SMarc Zyngier value = read_pmovsclr(); 6737755cec6SMarc Zyngier 6747755cec6SMarc Zyngier /* Write to clear flags */ 6757755cec6SMarc Zyngier value &= ARMV8_PMU_OVSR_MASK; 676df29ddf4SMarc Zyngier write_pmovsclr(value); 6777755cec6SMarc Zyngier 6787755cec6SMarc Zyngier return value; 6797755cec6SMarc Zyngier } 6807755cec6SMarc Zyngier 6817755cec6SMarc Zyngier static void armv8pmu_disable_user_access(void) 6827755cec6SMarc Zyngier { 683df29ddf4SMarc Zyngier write_pmuserenr(0); 6847755cec6SMarc Zyngier } 6857755cec6SMarc Zyngier 6867755cec6SMarc Zyngier static void armv8pmu_enable_user_access(struct arm_pmu *cpu_pmu) 6877755cec6SMarc Zyngier { 6887755cec6SMarc Zyngier int i; 6897755cec6SMarc Zyngier struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events); 6907755cec6SMarc Zyngier 6917755cec6SMarc Zyngier /* Clear any unused counters to avoid leaking their contents */ 6927755cec6SMarc Zyngier for_each_clear_bit(i, cpuc->used_mask, cpu_pmu->num_events) { 6937755cec6SMarc Zyngier if (i == ARMV8_IDX_CYCLE_COUNTER) 694df29ddf4SMarc Zyngier write_pmccntr(0); 6957755cec6SMarc Zyngier else 6967755cec6SMarc Zyngier armv8pmu_write_evcntr(i, 0); 6977755cec6SMarc Zyngier } 6987755cec6SMarc Zyngier 699df29ddf4SMarc Zyngier write_pmuserenr(0); 700df29ddf4SMarc Zyngier write_pmuserenr(ARMV8_PMU_USERENR_ER | ARMV8_PMU_USERENR_CR); 7017755cec6SMarc Zyngier } 7027755cec6SMarc Zyngier 7037755cec6SMarc Zyngier static void armv8pmu_enable_event(struct perf_event *event) 7047755cec6SMarc Zyngier { 7057755cec6SMarc Zyngier /* 7067755cec6SMarc Zyngier * Enable counter and interrupt, and set the counter to count 7077755cec6SMarc Zyngier * the event that we're interested in. 7087755cec6SMarc Zyngier */ 7097755cec6SMarc Zyngier 7107755cec6SMarc Zyngier /* 7117755cec6SMarc Zyngier * Disable counter 7127755cec6SMarc Zyngier */ 7137755cec6SMarc Zyngier armv8pmu_disable_event_counter(event); 7147755cec6SMarc Zyngier 7157755cec6SMarc Zyngier /* 7167755cec6SMarc Zyngier * Set event. 7177755cec6SMarc Zyngier */ 7187755cec6SMarc Zyngier armv8pmu_write_event_type(event); 7197755cec6SMarc Zyngier 7207755cec6SMarc Zyngier /* 7217755cec6SMarc Zyngier * Enable interrupt for this counter 7227755cec6SMarc Zyngier */ 7237755cec6SMarc Zyngier armv8pmu_enable_event_irq(event); 7247755cec6SMarc Zyngier 7257755cec6SMarc Zyngier /* 7267755cec6SMarc Zyngier * Enable counter 7277755cec6SMarc Zyngier */ 7287755cec6SMarc Zyngier armv8pmu_enable_event_counter(event); 7297755cec6SMarc Zyngier } 7307755cec6SMarc Zyngier 7317755cec6SMarc Zyngier static void armv8pmu_disable_event(struct perf_event *event) 7327755cec6SMarc Zyngier { 7337755cec6SMarc Zyngier /* 7347755cec6SMarc Zyngier * Disable counter 7357755cec6SMarc Zyngier */ 7367755cec6SMarc Zyngier armv8pmu_disable_event_counter(event); 7377755cec6SMarc Zyngier 7387755cec6SMarc Zyngier /* 7397755cec6SMarc Zyngier * Disable interrupt for this counter 7407755cec6SMarc Zyngier */ 7417755cec6SMarc Zyngier armv8pmu_disable_event_irq(event); 7427755cec6SMarc Zyngier } 7437755cec6SMarc Zyngier 7447755cec6SMarc Zyngier static void armv8pmu_start(struct arm_pmu *cpu_pmu) 7457755cec6SMarc Zyngier { 7467755cec6SMarc Zyngier struct perf_event_context *ctx; 7477755cec6SMarc Zyngier int nr_user = 0; 7487755cec6SMarc Zyngier 7497755cec6SMarc Zyngier ctx = perf_cpu_task_ctx(); 7507755cec6SMarc Zyngier if (ctx) 7517755cec6SMarc Zyngier nr_user = ctx->nr_user; 7527755cec6SMarc Zyngier 7537755cec6SMarc Zyngier if (sysctl_perf_user_access && nr_user) 7547755cec6SMarc Zyngier armv8pmu_enable_user_access(cpu_pmu); 7557755cec6SMarc Zyngier else 7567755cec6SMarc Zyngier armv8pmu_disable_user_access(); 7577755cec6SMarc Zyngier 7587755cec6SMarc Zyngier /* Enable all counters */ 7597755cec6SMarc Zyngier armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMU_PMCR_E); 7607755cec6SMarc Zyngier } 7617755cec6SMarc Zyngier 7627755cec6SMarc Zyngier static void armv8pmu_stop(struct arm_pmu *cpu_pmu) 7637755cec6SMarc Zyngier { 7647755cec6SMarc Zyngier /* Disable all counters */ 7657755cec6SMarc Zyngier armv8pmu_pmcr_write(armv8pmu_pmcr_read() & ~ARMV8_PMU_PMCR_E); 7667755cec6SMarc Zyngier } 7677755cec6SMarc Zyngier 7687755cec6SMarc Zyngier static irqreturn_t armv8pmu_handle_irq(struct arm_pmu *cpu_pmu) 7697755cec6SMarc Zyngier { 7707755cec6SMarc Zyngier u32 pmovsr; 7717755cec6SMarc Zyngier struct perf_sample_data data; 7727755cec6SMarc Zyngier struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events); 7737755cec6SMarc Zyngier struct pt_regs *regs; 7747755cec6SMarc Zyngier int idx; 7757755cec6SMarc Zyngier 7767755cec6SMarc Zyngier /* 7777755cec6SMarc Zyngier * Get and reset the IRQ flags 7787755cec6SMarc Zyngier */ 7797755cec6SMarc Zyngier pmovsr = armv8pmu_getreset_flags(); 7807755cec6SMarc Zyngier 7817755cec6SMarc Zyngier /* 7827755cec6SMarc Zyngier * Did an overflow occur? 7837755cec6SMarc Zyngier */ 7847755cec6SMarc Zyngier if (!armv8pmu_has_overflowed(pmovsr)) 7857755cec6SMarc Zyngier return IRQ_NONE; 7867755cec6SMarc Zyngier 7877755cec6SMarc Zyngier /* 7887755cec6SMarc Zyngier * Handle the counter(s) overflow(s) 7897755cec6SMarc Zyngier */ 7907755cec6SMarc Zyngier regs = get_irq_regs(); 7917755cec6SMarc Zyngier 7927755cec6SMarc Zyngier /* 7937755cec6SMarc Zyngier * Stop the PMU while processing the counter overflows 7947755cec6SMarc Zyngier * to prevent skews in group events. 7957755cec6SMarc Zyngier */ 7967755cec6SMarc Zyngier armv8pmu_stop(cpu_pmu); 7977755cec6SMarc Zyngier for (idx = 0; idx < cpu_pmu->num_events; ++idx) { 7987755cec6SMarc Zyngier struct perf_event *event = cpuc->events[idx]; 7997755cec6SMarc Zyngier struct hw_perf_event *hwc; 8007755cec6SMarc Zyngier 8017755cec6SMarc Zyngier /* Ignore if we don't have an event. */ 8027755cec6SMarc Zyngier if (!event) 8037755cec6SMarc Zyngier continue; 8047755cec6SMarc Zyngier 8057755cec6SMarc Zyngier /* 8067755cec6SMarc Zyngier * We have a single interrupt for all counters. Check that 8077755cec6SMarc Zyngier * each counter has overflowed before we process it. 8087755cec6SMarc Zyngier */ 8097755cec6SMarc Zyngier if (!armv8pmu_counter_has_overflowed(pmovsr, idx)) 8107755cec6SMarc Zyngier continue; 8117755cec6SMarc Zyngier 8127755cec6SMarc Zyngier hwc = &event->hw; 8137755cec6SMarc Zyngier armpmu_event_update(event); 8147755cec6SMarc Zyngier perf_sample_data_init(&data, 0, hwc->last_period); 8157755cec6SMarc Zyngier if (!armpmu_event_set_period(event)) 8167755cec6SMarc Zyngier continue; 8177755cec6SMarc Zyngier 8187755cec6SMarc Zyngier /* 8197755cec6SMarc Zyngier * Perf event overflow will queue the processing of the event as 8207755cec6SMarc Zyngier * an irq_work which will be taken care of in the handling of 8217755cec6SMarc Zyngier * IPI_IRQ_WORK. 8227755cec6SMarc Zyngier */ 8237755cec6SMarc Zyngier if (perf_event_overflow(event, &data, regs)) 8247755cec6SMarc Zyngier cpu_pmu->disable(event); 8257755cec6SMarc Zyngier } 8267755cec6SMarc Zyngier armv8pmu_start(cpu_pmu); 8277755cec6SMarc Zyngier 8287755cec6SMarc Zyngier return IRQ_HANDLED; 8297755cec6SMarc Zyngier } 8307755cec6SMarc Zyngier 8317755cec6SMarc Zyngier static int armv8pmu_get_single_idx(struct pmu_hw_events *cpuc, 8327755cec6SMarc Zyngier struct arm_pmu *cpu_pmu) 8337755cec6SMarc Zyngier { 8347755cec6SMarc Zyngier int idx; 8357755cec6SMarc Zyngier 8367755cec6SMarc Zyngier for (idx = ARMV8_IDX_COUNTER0; idx < cpu_pmu->num_events; idx++) { 8377755cec6SMarc Zyngier if (!test_and_set_bit(idx, cpuc->used_mask)) 8387755cec6SMarc Zyngier return idx; 8397755cec6SMarc Zyngier } 8407755cec6SMarc Zyngier return -EAGAIN; 8417755cec6SMarc Zyngier } 8427755cec6SMarc Zyngier 8437755cec6SMarc Zyngier static int armv8pmu_get_chain_idx(struct pmu_hw_events *cpuc, 8447755cec6SMarc Zyngier struct arm_pmu *cpu_pmu) 8457755cec6SMarc Zyngier { 8467755cec6SMarc Zyngier int idx; 8477755cec6SMarc Zyngier 8487755cec6SMarc Zyngier /* 8497755cec6SMarc Zyngier * Chaining requires two consecutive event counters, where 8507755cec6SMarc Zyngier * the lower idx must be even. 8517755cec6SMarc Zyngier */ 8527755cec6SMarc Zyngier for (idx = ARMV8_IDX_COUNTER0 + 1; idx < cpu_pmu->num_events; idx += 2) { 8537755cec6SMarc Zyngier if (!test_and_set_bit(idx, cpuc->used_mask)) { 8547755cec6SMarc Zyngier /* Check if the preceding even counter is available */ 8557755cec6SMarc Zyngier if (!test_and_set_bit(idx - 1, cpuc->used_mask)) 8567755cec6SMarc Zyngier return idx; 8577755cec6SMarc Zyngier /* Release the Odd counter */ 8587755cec6SMarc Zyngier clear_bit(idx, cpuc->used_mask); 8597755cec6SMarc Zyngier } 8607755cec6SMarc Zyngier } 8617755cec6SMarc Zyngier return -EAGAIN; 8627755cec6SMarc Zyngier } 8637755cec6SMarc Zyngier 8647755cec6SMarc Zyngier static int armv8pmu_get_event_idx(struct pmu_hw_events *cpuc, 8657755cec6SMarc Zyngier struct perf_event *event) 8667755cec6SMarc Zyngier { 8677755cec6SMarc Zyngier struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); 8687755cec6SMarc Zyngier struct hw_perf_event *hwc = &event->hw; 8697755cec6SMarc Zyngier unsigned long evtype = hwc->config_base & ARMV8_PMU_EVTYPE_EVENT; 8707755cec6SMarc Zyngier 8717755cec6SMarc Zyngier /* Always prefer to place a cycle counter into the cycle counter. */ 8727755cec6SMarc Zyngier if (evtype == ARMV8_PMUV3_PERFCTR_CPU_CYCLES) { 8737755cec6SMarc Zyngier if (!test_and_set_bit(ARMV8_IDX_CYCLE_COUNTER, cpuc->used_mask)) 8747755cec6SMarc Zyngier return ARMV8_IDX_CYCLE_COUNTER; 8757755cec6SMarc Zyngier else if (armv8pmu_event_is_64bit(event) && 8767755cec6SMarc Zyngier armv8pmu_event_want_user_access(event) && 8777755cec6SMarc Zyngier !armv8pmu_has_long_event(cpu_pmu)) 8787755cec6SMarc Zyngier return -EAGAIN; 8797755cec6SMarc Zyngier } 8807755cec6SMarc Zyngier 8817755cec6SMarc Zyngier /* 8827755cec6SMarc Zyngier * Otherwise use events counters 8837755cec6SMarc Zyngier */ 8847755cec6SMarc Zyngier if (armv8pmu_event_is_chained(event)) 8857755cec6SMarc Zyngier return armv8pmu_get_chain_idx(cpuc, cpu_pmu); 8867755cec6SMarc Zyngier else 8877755cec6SMarc Zyngier return armv8pmu_get_single_idx(cpuc, cpu_pmu); 8887755cec6SMarc Zyngier } 8897755cec6SMarc Zyngier 8907755cec6SMarc Zyngier static void armv8pmu_clear_event_idx(struct pmu_hw_events *cpuc, 8917755cec6SMarc Zyngier struct perf_event *event) 8927755cec6SMarc Zyngier { 8937755cec6SMarc Zyngier int idx = event->hw.idx; 8947755cec6SMarc Zyngier 8957755cec6SMarc Zyngier clear_bit(idx, cpuc->used_mask); 8967755cec6SMarc Zyngier if (armv8pmu_event_is_chained(event)) 8977755cec6SMarc Zyngier clear_bit(idx - 1, cpuc->used_mask); 8987755cec6SMarc Zyngier } 8997755cec6SMarc Zyngier 9007755cec6SMarc Zyngier static int armv8pmu_user_event_idx(struct perf_event *event) 9017755cec6SMarc Zyngier { 9027755cec6SMarc Zyngier if (!sysctl_perf_user_access || !armv8pmu_event_has_user_read(event)) 9037755cec6SMarc Zyngier return 0; 9047755cec6SMarc Zyngier 9057755cec6SMarc Zyngier /* 9067755cec6SMarc Zyngier * We remap the cycle counter index to 32 to 9077755cec6SMarc Zyngier * match the offset applied to the rest of 9087755cec6SMarc Zyngier * the counter indices. 9097755cec6SMarc Zyngier */ 9107755cec6SMarc Zyngier if (event->hw.idx == ARMV8_IDX_CYCLE_COUNTER) 9117755cec6SMarc Zyngier return ARMV8_IDX_CYCLE_COUNTER_USER; 9127755cec6SMarc Zyngier 9137755cec6SMarc Zyngier return event->hw.idx; 9147755cec6SMarc Zyngier } 9157755cec6SMarc Zyngier 9167755cec6SMarc Zyngier /* 9177755cec6SMarc Zyngier * Add an event filter to a given event. 9187755cec6SMarc Zyngier */ 9197755cec6SMarc Zyngier static int armv8pmu_set_event_filter(struct hw_perf_event *event, 9207755cec6SMarc Zyngier struct perf_event_attr *attr) 9217755cec6SMarc Zyngier { 9227755cec6SMarc Zyngier unsigned long config_base = 0; 9237755cec6SMarc Zyngier 9247755cec6SMarc Zyngier if (attr->exclude_idle) 9257755cec6SMarc Zyngier return -EPERM; 9267755cec6SMarc Zyngier 9277755cec6SMarc Zyngier /* 9287755cec6SMarc Zyngier * If we're running in hyp mode, then we *are* the hypervisor. 9297755cec6SMarc Zyngier * Therefore we ignore exclude_hv in this configuration, since 9307755cec6SMarc Zyngier * there's no hypervisor to sample anyway. This is consistent 9317755cec6SMarc Zyngier * with other architectures (x86 and Power). 9327755cec6SMarc Zyngier */ 9337755cec6SMarc Zyngier if (is_kernel_in_hyp_mode()) { 9347755cec6SMarc Zyngier if (!attr->exclude_kernel && !attr->exclude_host) 9357755cec6SMarc Zyngier config_base |= ARMV8_PMU_INCLUDE_EL2; 9367755cec6SMarc Zyngier if (attr->exclude_guest) 9377755cec6SMarc Zyngier config_base |= ARMV8_PMU_EXCLUDE_EL1; 9387755cec6SMarc Zyngier if (attr->exclude_host) 9397755cec6SMarc Zyngier config_base |= ARMV8_PMU_EXCLUDE_EL0; 9407755cec6SMarc Zyngier } else { 9417755cec6SMarc Zyngier if (!attr->exclude_hv && !attr->exclude_host) 9427755cec6SMarc Zyngier config_base |= ARMV8_PMU_INCLUDE_EL2; 9437755cec6SMarc Zyngier } 9447755cec6SMarc Zyngier 9457755cec6SMarc Zyngier /* 9467755cec6SMarc Zyngier * Filter out !VHE kernels and guest kernels 9477755cec6SMarc Zyngier */ 9487755cec6SMarc Zyngier if (attr->exclude_kernel) 9497755cec6SMarc Zyngier config_base |= ARMV8_PMU_EXCLUDE_EL1; 9507755cec6SMarc Zyngier 9517755cec6SMarc Zyngier if (attr->exclude_user) 9527755cec6SMarc Zyngier config_base |= ARMV8_PMU_EXCLUDE_EL0; 9537755cec6SMarc Zyngier 9547755cec6SMarc Zyngier /* 9557755cec6SMarc Zyngier * Install the filter into config_base as this is used to 9567755cec6SMarc Zyngier * construct the event type. 9577755cec6SMarc Zyngier */ 9587755cec6SMarc Zyngier event->config_base = config_base; 9597755cec6SMarc Zyngier 9607755cec6SMarc Zyngier return 0; 9617755cec6SMarc Zyngier } 9627755cec6SMarc Zyngier 9637755cec6SMarc Zyngier static void armv8pmu_reset(void *info) 9647755cec6SMarc Zyngier { 9657755cec6SMarc Zyngier struct arm_pmu *cpu_pmu = (struct arm_pmu *)info; 9667755cec6SMarc Zyngier u32 pmcr; 9677755cec6SMarc Zyngier 9687755cec6SMarc Zyngier /* The counter and interrupt enable registers are unknown at reset. */ 9697755cec6SMarc Zyngier armv8pmu_disable_counter(U32_MAX); 9707755cec6SMarc Zyngier armv8pmu_disable_intens(U32_MAX); 9717755cec6SMarc Zyngier 9727755cec6SMarc Zyngier /* Clear the counters we flip at guest entry/exit */ 9737755cec6SMarc Zyngier kvm_clr_pmu_events(U32_MAX); 9747755cec6SMarc Zyngier 9757755cec6SMarc Zyngier /* 9767755cec6SMarc Zyngier * Initialize & Reset PMNC. Request overflow interrupt for 9777755cec6SMarc Zyngier * 64 bit cycle counter but cheat in armv8pmu_write_counter(). 9787755cec6SMarc Zyngier */ 9797755cec6SMarc Zyngier pmcr = ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C | ARMV8_PMU_PMCR_LC; 9807755cec6SMarc Zyngier 9817755cec6SMarc Zyngier /* Enable long event counter support where available */ 9827755cec6SMarc Zyngier if (armv8pmu_has_long_event(cpu_pmu)) 9837755cec6SMarc Zyngier pmcr |= ARMV8_PMU_PMCR_LP; 9847755cec6SMarc Zyngier 9857755cec6SMarc Zyngier armv8pmu_pmcr_write(pmcr); 9867755cec6SMarc Zyngier } 9877755cec6SMarc Zyngier 9887755cec6SMarc Zyngier static int __armv8_pmuv3_map_event(struct perf_event *event, 9897755cec6SMarc Zyngier const unsigned (*extra_event_map) 9907755cec6SMarc Zyngier [PERF_COUNT_HW_MAX], 9917755cec6SMarc Zyngier const unsigned (*extra_cache_map) 9927755cec6SMarc Zyngier [PERF_COUNT_HW_CACHE_MAX] 9937755cec6SMarc Zyngier [PERF_COUNT_HW_CACHE_OP_MAX] 9947755cec6SMarc Zyngier [PERF_COUNT_HW_CACHE_RESULT_MAX]) 9957755cec6SMarc Zyngier { 9967755cec6SMarc Zyngier int hw_event_id; 9977755cec6SMarc Zyngier struct arm_pmu *armpmu = to_arm_pmu(event->pmu); 9987755cec6SMarc Zyngier 9997755cec6SMarc Zyngier hw_event_id = armpmu_map_event(event, &armv8_pmuv3_perf_map, 10007755cec6SMarc Zyngier &armv8_pmuv3_perf_cache_map, 10017755cec6SMarc Zyngier ARMV8_PMU_EVTYPE_EVENT); 10027755cec6SMarc Zyngier 10037755cec6SMarc Zyngier /* 10047755cec6SMarc Zyngier * CHAIN events only work when paired with an adjacent counter, and it 10057755cec6SMarc Zyngier * never makes sense for a user to open one in isolation, as they'll be 10067755cec6SMarc Zyngier * rotated arbitrarily. 10077755cec6SMarc Zyngier */ 10087755cec6SMarc Zyngier if (hw_event_id == ARMV8_PMUV3_PERFCTR_CHAIN) 10097755cec6SMarc Zyngier return -EINVAL; 10107755cec6SMarc Zyngier 10117755cec6SMarc Zyngier if (armv8pmu_event_is_64bit(event)) 10127755cec6SMarc Zyngier event->hw.flags |= ARMPMU_EVT_64BIT; 10137755cec6SMarc Zyngier 10147755cec6SMarc Zyngier /* 10157755cec6SMarc Zyngier * User events must be allocated into a single counter, and so 10167755cec6SMarc Zyngier * must not be chained. 10177755cec6SMarc Zyngier * 10187755cec6SMarc Zyngier * Most 64-bit events require long counter support, but 64-bit 10197755cec6SMarc Zyngier * CPU_CYCLES events can be placed into the dedicated cycle 10207755cec6SMarc Zyngier * counter when this is free. 10217755cec6SMarc Zyngier */ 10227755cec6SMarc Zyngier if (armv8pmu_event_want_user_access(event)) { 10237755cec6SMarc Zyngier if (!(event->attach_state & PERF_ATTACH_TASK)) 10247755cec6SMarc Zyngier return -EINVAL; 10257755cec6SMarc Zyngier if (armv8pmu_event_is_64bit(event) && 10267755cec6SMarc Zyngier (hw_event_id != ARMV8_PMUV3_PERFCTR_CPU_CYCLES) && 10277755cec6SMarc Zyngier !armv8pmu_has_long_event(armpmu)) 10287755cec6SMarc Zyngier return -EOPNOTSUPP; 10297755cec6SMarc Zyngier 10307755cec6SMarc Zyngier event->hw.flags |= PERF_EVENT_FLAG_USER_READ_CNT; 10317755cec6SMarc Zyngier } 10327755cec6SMarc Zyngier 10337755cec6SMarc Zyngier /* Only expose micro/arch events supported by this PMU */ 10347755cec6SMarc Zyngier if ((hw_event_id > 0) && (hw_event_id < ARMV8_PMUV3_MAX_COMMON_EVENTS) 10357755cec6SMarc Zyngier && test_bit(hw_event_id, armpmu->pmceid_bitmap)) { 10367755cec6SMarc Zyngier return hw_event_id; 10377755cec6SMarc Zyngier } 10387755cec6SMarc Zyngier 10397755cec6SMarc Zyngier return armpmu_map_event(event, extra_event_map, extra_cache_map, 10407755cec6SMarc Zyngier ARMV8_PMU_EVTYPE_EVENT); 10417755cec6SMarc Zyngier } 10427755cec6SMarc Zyngier 10437755cec6SMarc Zyngier static int armv8_pmuv3_map_event(struct perf_event *event) 10447755cec6SMarc Zyngier { 10457755cec6SMarc Zyngier return __armv8_pmuv3_map_event(event, NULL, NULL); 10467755cec6SMarc Zyngier } 10477755cec6SMarc Zyngier 10487755cec6SMarc Zyngier static int armv8_a53_map_event(struct perf_event *event) 10497755cec6SMarc Zyngier { 10507755cec6SMarc Zyngier return __armv8_pmuv3_map_event(event, NULL, &armv8_a53_perf_cache_map); 10517755cec6SMarc Zyngier } 10527755cec6SMarc Zyngier 10537755cec6SMarc Zyngier static int armv8_a57_map_event(struct perf_event *event) 10547755cec6SMarc Zyngier { 10557755cec6SMarc Zyngier return __armv8_pmuv3_map_event(event, NULL, &armv8_a57_perf_cache_map); 10567755cec6SMarc Zyngier } 10577755cec6SMarc Zyngier 10587755cec6SMarc Zyngier static int armv8_a73_map_event(struct perf_event *event) 10597755cec6SMarc Zyngier { 10607755cec6SMarc Zyngier return __armv8_pmuv3_map_event(event, NULL, &armv8_a73_perf_cache_map); 10617755cec6SMarc Zyngier } 10627755cec6SMarc Zyngier 10637755cec6SMarc Zyngier static int armv8_thunder_map_event(struct perf_event *event) 10647755cec6SMarc Zyngier { 10657755cec6SMarc Zyngier return __armv8_pmuv3_map_event(event, NULL, 10667755cec6SMarc Zyngier &armv8_thunder_perf_cache_map); 10677755cec6SMarc Zyngier } 10687755cec6SMarc Zyngier 10697755cec6SMarc Zyngier static int armv8_vulcan_map_event(struct perf_event *event) 10707755cec6SMarc Zyngier { 10717755cec6SMarc Zyngier return __armv8_pmuv3_map_event(event, NULL, 10727755cec6SMarc Zyngier &armv8_vulcan_perf_cache_map); 10737755cec6SMarc Zyngier } 10747755cec6SMarc Zyngier 10757755cec6SMarc Zyngier struct armv8pmu_probe_info { 10767755cec6SMarc Zyngier struct arm_pmu *pmu; 10777755cec6SMarc Zyngier bool present; 10787755cec6SMarc Zyngier }; 10797755cec6SMarc Zyngier 10807755cec6SMarc Zyngier static void __armv8pmu_probe_pmu(void *info) 10817755cec6SMarc Zyngier { 10827755cec6SMarc Zyngier struct armv8pmu_probe_info *probe = info; 10837755cec6SMarc Zyngier struct arm_pmu *cpu_pmu = probe->pmu; 10847755cec6SMarc Zyngier u64 pmceid_raw[2]; 10857755cec6SMarc Zyngier u32 pmceid[2]; 10867755cec6SMarc Zyngier int pmuver; 10877755cec6SMarc Zyngier 1088df29ddf4SMarc Zyngier pmuver = read_pmuver(); 108971143277SZaid Al-Bassam if (!pmuv3_implemented(pmuver)) 10907755cec6SMarc Zyngier return; 10917755cec6SMarc Zyngier 10927755cec6SMarc Zyngier cpu_pmu->pmuver = pmuver; 10937755cec6SMarc Zyngier probe->present = true; 10947755cec6SMarc Zyngier 10957755cec6SMarc Zyngier /* Read the nb of CNTx counters supported from PMNC */ 10967755cec6SMarc Zyngier cpu_pmu->num_events = (armv8pmu_pmcr_read() >> ARMV8_PMU_PMCR_N_SHIFT) 10977755cec6SMarc Zyngier & ARMV8_PMU_PMCR_N_MASK; 10987755cec6SMarc Zyngier 10997755cec6SMarc Zyngier /* Add the CPU cycles counter */ 11007755cec6SMarc Zyngier cpu_pmu->num_events += 1; 11017755cec6SMarc Zyngier 1102df29ddf4SMarc Zyngier pmceid[0] = pmceid_raw[0] = read_pmceid0(); 1103df29ddf4SMarc Zyngier pmceid[1] = pmceid_raw[1] = read_pmceid1(); 11047755cec6SMarc Zyngier 11057755cec6SMarc Zyngier bitmap_from_arr32(cpu_pmu->pmceid_bitmap, 11067755cec6SMarc Zyngier pmceid, ARMV8_PMUV3_MAX_COMMON_EVENTS); 11077755cec6SMarc Zyngier 11087755cec6SMarc Zyngier pmceid[0] = pmceid_raw[0] >> 32; 11097755cec6SMarc Zyngier pmceid[1] = pmceid_raw[1] >> 32; 11107755cec6SMarc Zyngier 11117755cec6SMarc Zyngier bitmap_from_arr32(cpu_pmu->pmceid_ext_bitmap, 11127755cec6SMarc Zyngier pmceid, ARMV8_PMUV3_MAX_COMMON_EVENTS); 11137755cec6SMarc Zyngier 1114df29ddf4SMarc Zyngier /* store PMMIR register for sysfs */ 111571143277SZaid Al-Bassam if (is_pmuv3p4(pmuver) && (pmceid_raw[1] & BIT(31))) 1116df29ddf4SMarc Zyngier cpu_pmu->reg_pmmir = read_pmmir(); 11177755cec6SMarc Zyngier else 11187755cec6SMarc Zyngier cpu_pmu->reg_pmmir = 0; 11197755cec6SMarc Zyngier } 11207755cec6SMarc Zyngier 11217755cec6SMarc Zyngier static int armv8pmu_probe_pmu(struct arm_pmu *cpu_pmu) 11227755cec6SMarc Zyngier { 11237755cec6SMarc Zyngier struct armv8pmu_probe_info probe = { 11247755cec6SMarc Zyngier .pmu = cpu_pmu, 11257755cec6SMarc Zyngier .present = false, 11267755cec6SMarc Zyngier }; 11277755cec6SMarc Zyngier int ret; 11287755cec6SMarc Zyngier 11297755cec6SMarc Zyngier ret = smp_call_function_any(&cpu_pmu->supported_cpus, 11307755cec6SMarc Zyngier __armv8pmu_probe_pmu, 11317755cec6SMarc Zyngier &probe, 1); 11327755cec6SMarc Zyngier if (ret) 11337755cec6SMarc Zyngier return ret; 11347755cec6SMarc Zyngier 11357755cec6SMarc Zyngier return probe.present ? 0 : -ENODEV; 11367755cec6SMarc Zyngier } 11377755cec6SMarc Zyngier 11387755cec6SMarc Zyngier static void armv8pmu_disable_user_access_ipi(void *unused) 11397755cec6SMarc Zyngier { 11407755cec6SMarc Zyngier armv8pmu_disable_user_access(); 11417755cec6SMarc Zyngier } 11427755cec6SMarc Zyngier 11437755cec6SMarc Zyngier static int armv8pmu_proc_user_access_handler(struct ctl_table *table, int write, 11447755cec6SMarc Zyngier void *buffer, size_t *lenp, loff_t *ppos) 11457755cec6SMarc Zyngier { 11467755cec6SMarc Zyngier int ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); 11477755cec6SMarc Zyngier if (ret || !write || sysctl_perf_user_access) 11487755cec6SMarc Zyngier return ret; 11497755cec6SMarc Zyngier 11507755cec6SMarc Zyngier on_each_cpu(armv8pmu_disable_user_access_ipi, NULL, 1); 11517755cec6SMarc Zyngier return 0; 11527755cec6SMarc Zyngier } 11537755cec6SMarc Zyngier 11547755cec6SMarc Zyngier static struct ctl_table armv8_pmu_sysctl_table[] = { 11557755cec6SMarc Zyngier { 11567755cec6SMarc Zyngier .procname = "perf_user_access", 11577755cec6SMarc Zyngier .data = &sysctl_perf_user_access, 11587755cec6SMarc Zyngier .maxlen = sizeof(unsigned int), 11597755cec6SMarc Zyngier .mode = 0644, 11607755cec6SMarc Zyngier .proc_handler = armv8pmu_proc_user_access_handler, 11617755cec6SMarc Zyngier .extra1 = SYSCTL_ZERO, 11627755cec6SMarc Zyngier .extra2 = SYSCTL_ONE, 11637755cec6SMarc Zyngier }, 11647755cec6SMarc Zyngier { } 11657755cec6SMarc Zyngier }; 11667755cec6SMarc Zyngier 11677755cec6SMarc Zyngier static void armv8_pmu_register_sysctl_table(void) 11687755cec6SMarc Zyngier { 11697755cec6SMarc Zyngier static u32 tbl_registered = 0; 11707755cec6SMarc Zyngier 11717755cec6SMarc Zyngier if (!cmpxchg_relaxed(&tbl_registered, 0, 1)) 11727755cec6SMarc Zyngier register_sysctl("kernel", armv8_pmu_sysctl_table); 11737755cec6SMarc Zyngier } 11747755cec6SMarc Zyngier 11757755cec6SMarc Zyngier static int armv8_pmu_init(struct arm_pmu *cpu_pmu, char *name, 11767755cec6SMarc Zyngier int (*map_event)(struct perf_event *event), 11777755cec6SMarc Zyngier const struct attribute_group *events, 11787755cec6SMarc Zyngier const struct attribute_group *format, 11797755cec6SMarc Zyngier const struct attribute_group *caps) 11807755cec6SMarc Zyngier { 11817755cec6SMarc Zyngier int ret = armv8pmu_probe_pmu(cpu_pmu); 11827755cec6SMarc Zyngier if (ret) 11837755cec6SMarc Zyngier return ret; 11847755cec6SMarc Zyngier 11857755cec6SMarc Zyngier cpu_pmu->handle_irq = armv8pmu_handle_irq; 11867755cec6SMarc Zyngier cpu_pmu->enable = armv8pmu_enable_event; 11877755cec6SMarc Zyngier cpu_pmu->disable = armv8pmu_disable_event; 11887755cec6SMarc Zyngier cpu_pmu->read_counter = armv8pmu_read_counter; 11897755cec6SMarc Zyngier cpu_pmu->write_counter = armv8pmu_write_counter; 11907755cec6SMarc Zyngier cpu_pmu->get_event_idx = armv8pmu_get_event_idx; 11917755cec6SMarc Zyngier cpu_pmu->clear_event_idx = armv8pmu_clear_event_idx; 11927755cec6SMarc Zyngier cpu_pmu->start = armv8pmu_start; 11937755cec6SMarc Zyngier cpu_pmu->stop = armv8pmu_stop; 11947755cec6SMarc Zyngier cpu_pmu->reset = armv8pmu_reset; 11957755cec6SMarc Zyngier cpu_pmu->set_event_filter = armv8pmu_set_event_filter; 11967755cec6SMarc Zyngier 11977755cec6SMarc Zyngier cpu_pmu->pmu.event_idx = armv8pmu_user_event_idx; 11987755cec6SMarc Zyngier 11997755cec6SMarc Zyngier cpu_pmu->name = name; 12007755cec6SMarc Zyngier cpu_pmu->map_event = map_event; 12017755cec6SMarc Zyngier cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = events ? 12027755cec6SMarc Zyngier events : &armv8_pmuv3_events_attr_group; 12037755cec6SMarc Zyngier cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] = format ? 12047755cec6SMarc Zyngier format : &armv8_pmuv3_format_attr_group; 12057755cec6SMarc Zyngier cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_CAPS] = caps ? 12067755cec6SMarc Zyngier caps : &armv8_pmuv3_caps_attr_group; 12077755cec6SMarc Zyngier 12087755cec6SMarc Zyngier armv8_pmu_register_sysctl_table(); 12097755cec6SMarc Zyngier return 0; 12107755cec6SMarc Zyngier } 12117755cec6SMarc Zyngier 12127755cec6SMarc Zyngier static int armv8_pmu_init_nogroups(struct arm_pmu *cpu_pmu, char *name, 12137755cec6SMarc Zyngier int (*map_event)(struct perf_event *event)) 12147755cec6SMarc Zyngier { 12157755cec6SMarc Zyngier return armv8_pmu_init(cpu_pmu, name, map_event, NULL, NULL, NULL); 12167755cec6SMarc Zyngier } 12177755cec6SMarc Zyngier 12187755cec6SMarc Zyngier #define PMUV3_INIT_SIMPLE(name) \ 12197755cec6SMarc Zyngier static int name##_pmu_init(struct arm_pmu *cpu_pmu) \ 12207755cec6SMarc Zyngier { \ 12217755cec6SMarc Zyngier return armv8_pmu_init_nogroups(cpu_pmu, #name, armv8_pmuv3_map_event);\ 12227755cec6SMarc Zyngier } 12237755cec6SMarc Zyngier 12247755cec6SMarc Zyngier PMUV3_INIT_SIMPLE(armv8_pmuv3) 12257755cec6SMarc Zyngier 12267755cec6SMarc Zyngier PMUV3_INIT_SIMPLE(armv8_cortex_a34) 12277755cec6SMarc Zyngier PMUV3_INIT_SIMPLE(armv8_cortex_a55) 12287755cec6SMarc Zyngier PMUV3_INIT_SIMPLE(armv8_cortex_a65) 12297755cec6SMarc Zyngier PMUV3_INIT_SIMPLE(armv8_cortex_a75) 12307755cec6SMarc Zyngier PMUV3_INIT_SIMPLE(armv8_cortex_a76) 12317755cec6SMarc Zyngier PMUV3_INIT_SIMPLE(armv8_cortex_a77) 12327755cec6SMarc Zyngier PMUV3_INIT_SIMPLE(armv8_cortex_a78) 12337755cec6SMarc Zyngier PMUV3_INIT_SIMPLE(armv9_cortex_a510) 12347755cec6SMarc Zyngier PMUV3_INIT_SIMPLE(armv9_cortex_a710) 12357755cec6SMarc Zyngier PMUV3_INIT_SIMPLE(armv8_cortex_x1) 12367755cec6SMarc Zyngier PMUV3_INIT_SIMPLE(armv9_cortex_x2) 12377755cec6SMarc Zyngier PMUV3_INIT_SIMPLE(armv8_neoverse_e1) 12387755cec6SMarc Zyngier PMUV3_INIT_SIMPLE(armv8_neoverse_n1) 12397755cec6SMarc Zyngier PMUV3_INIT_SIMPLE(armv9_neoverse_n2) 12407755cec6SMarc Zyngier PMUV3_INIT_SIMPLE(armv8_neoverse_v1) 12417755cec6SMarc Zyngier 12427755cec6SMarc Zyngier PMUV3_INIT_SIMPLE(armv8_nvidia_carmel) 12437755cec6SMarc Zyngier PMUV3_INIT_SIMPLE(armv8_nvidia_denver) 12447755cec6SMarc Zyngier 12457755cec6SMarc Zyngier static int armv8_a35_pmu_init(struct arm_pmu *cpu_pmu) 12467755cec6SMarc Zyngier { 12477755cec6SMarc Zyngier return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a35", 12487755cec6SMarc Zyngier armv8_a53_map_event); 12497755cec6SMarc Zyngier } 12507755cec6SMarc Zyngier 12517755cec6SMarc Zyngier static int armv8_a53_pmu_init(struct arm_pmu *cpu_pmu) 12527755cec6SMarc Zyngier { 12537755cec6SMarc Zyngier return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a53", 12547755cec6SMarc Zyngier armv8_a53_map_event); 12557755cec6SMarc Zyngier } 12567755cec6SMarc Zyngier 12577755cec6SMarc Zyngier static int armv8_a57_pmu_init(struct arm_pmu *cpu_pmu) 12587755cec6SMarc Zyngier { 12597755cec6SMarc Zyngier return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a57", 12607755cec6SMarc Zyngier armv8_a57_map_event); 12617755cec6SMarc Zyngier } 12627755cec6SMarc Zyngier 12637755cec6SMarc Zyngier static int armv8_a72_pmu_init(struct arm_pmu *cpu_pmu) 12647755cec6SMarc Zyngier { 12657755cec6SMarc Zyngier return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a72", 12667755cec6SMarc Zyngier armv8_a57_map_event); 12677755cec6SMarc Zyngier } 12687755cec6SMarc Zyngier 12697755cec6SMarc Zyngier static int armv8_a73_pmu_init(struct arm_pmu *cpu_pmu) 12707755cec6SMarc Zyngier { 12717755cec6SMarc Zyngier return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a73", 12727755cec6SMarc Zyngier armv8_a73_map_event); 12737755cec6SMarc Zyngier } 12747755cec6SMarc Zyngier 12757755cec6SMarc Zyngier static int armv8_thunder_pmu_init(struct arm_pmu *cpu_pmu) 12767755cec6SMarc Zyngier { 12777755cec6SMarc Zyngier return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cavium_thunder", 12787755cec6SMarc Zyngier armv8_thunder_map_event); 12797755cec6SMarc Zyngier } 12807755cec6SMarc Zyngier 12817755cec6SMarc Zyngier static int armv8_vulcan_pmu_init(struct arm_pmu *cpu_pmu) 12827755cec6SMarc Zyngier { 12837755cec6SMarc Zyngier return armv8_pmu_init_nogroups(cpu_pmu, "armv8_brcm_vulcan", 12847755cec6SMarc Zyngier armv8_vulcan_map_event); 12857755cec6SMarc Zyngier } 12867755cec6SMarc Zyngier 12877755cec6SMarc Zyngier static const struct of_device_id armv8_pmu_of_device_ids[] = { 12887755cec6SMarc Zyngier {.compatible = "arm,armv8-pmuv3", .data = armv8_pmuv3_pmu_init}, 12897755cec6SMarc Zyngier {.compatible = "arm,cortex-a34-pmu", .data = armv8_cortex_a34_pmu_init}, 12907755cec6SMarc Zyngier {.compatible = "arm,cortex-a35-pmu", .data = armv8_a35_pmu_init}, 12917755cec6SMarc Zyngier {.compatible = "arm,cortex-a53-pmu", .data = armv8_a53_pmu_init}, 12927755cec6SMarc Zyngier {.compatible = "arm,cortex-a55-pmu", .data = armv8_cortex_a55_pmu_init}, 12937755cec6SMarc Zyngier {.compatible = "arm,cortex-a57-pmu", .data = armv8_a57_pmu_init}, 12947755cec6SMarc Zyngier {.compatible = "arm,cortex-a65-pmu", .data = armv8_cortex_a65_pmu_init}, 12957755cec6SMarc Zyngier {.compatible = "arm,cortex-a72-pmu", .data = armv8_a72_pmu_init}, 12967755cec6SMarc Zyngier {.compatible = "arm,cortex-a73-pmu", .data = armv8_a73_pmu_init}, 12977755cec6SMarc Zyngier {.compatible = "arm,cortex-a75-pmu", .data = armv8_cortex_a75_pmu_init}, 12987755cec6SMarc Zyngier {.compatible = "arm,cortex-a76-pmu", .data = armv8_cortex_a76_pmu_init}, 12997755cec6SMarc Zyngier {.compatible = "arm,cortex-a77-pmu", .data = armv8_cortex_a77_pmu_init}, 13007755cec6SMarc Zyngier {.compatible = "arm,cortex-a78-pmu", .data = armv8_cortex_a78_pmu_init}, 13017755cec6SMarc Zyngier {.compatible = "arm,cortex-a510-pmu", .data = armv9_cortex_a510_pmu_init}, 13027755cec6SMarc Zyngier {.compatible = "arm,cortex-a710-pmu", .data = armv9_cortex_a710_pmu_init}, 13037755cec6SMarc Zyngier {.compatible = "arm,cortex-x1-pmu", .data = armv8_cortex_x1_pmu_init}, 13047755cec6SMarc Zyngier {.compatible = "arm,cortex-x2-pmu", .data = armv9_cortex_x2_pmu_init}, 13057755cec6SMarc Zyngier {.compatible = "arm,neoverse-e1-pmu", .data = armv8_neoverse_e1_pmu_init}, 13067755cec6SMarc Zyngier {.compatible = "arm,neoverse-n1-pmu", .data = armv8_neoverse_n1_pmu_init}, 13077755cec6SMarc Zyngier {.compatible = "arm,neoverse-n2-pmu", .data = armv9_neoverse_n2_pmu_init}, 13087755cec6SMarc Zyngier {.compatible = "arm,neoverse-v1-pmu", .data = armv8_neoverse_v1_pmu_init}, 13097755cec6SMarc Zyngier {.compatible = "cavium,thunder-pmu", .data = armv8_thunder_pmu_init}, 13107755cec6SMarc Zyngier {.compatible = "brcm,vulcan-pmu", .data = armv8_vulcan_pmu_init}, 13117755cec6SMarc Zyngier {.compatible = "nvidia,carmel-pmu", .data = armv8_nvidia_carmel_pmu_init}, 13127755cec6SMarc Zyngier {.compatible = "nvidia,denver-pmu", .data = armv8_nvidia_denver_pmu_init}, 13137755cec6SMarc Zyngier {}, 13147755cec6SMarc Zyngier }; 13157755cec6SMarc Zyngier 13167755cec6SMarc Zyngier static int armv8_pmu_device_probe(struct platform_device *pdev) 13177755cec6SMarc Zyngier { 13187755cec6SMarc Zyngier return arm_pmu_device_probe(pdev, armv8_pmu_of_device_ids, NULL); 13197755cec6SMarc Zyngier } 13207755cec6SMarc Zyngier 13217755cec6SMarc Zyngier static struct platform_driver armv8_pmu_driver = { 13227755cec6SMarc Zyngier .driver = { 13237755cec6SMarc Zyngier .name = ARMV8_PMU_PDEV_NAME, 13247755cec6SMarc Zyngier .of_match_table = armv8_pmu_of_device_ids, 13257755cec6SMarc Zyngier .suppress_bind_attrs = true, 13267755cec6SMarc Zyngier }, 13277755cec6SMarc Zyngier .probe = armv8_pmu_device_probe, 13287755cec6SMarc Zyngier }; 13297755cec6SMarc Zyngier 13307755cec6SMarc Zyngier static int __init armv8_pmu_driver_init(void) 13317755cec6SMarc Zyngier { 13327755cec6SMarc Zyngier if (acpi_disabled) 13337755cec6SMarc Zyngier return platform_driver_register(&armv8_pmu_driver); 13347755cec6SMarc Zyngier else 13357755cec6SMarc Zyngier return arm_pmu_acpi_probe(armv8_pmuv3_pmu_init); 13367755cec6SMarc Zyngier } 13377755cec6SMarc Zyngier device_initcall(armv8_pmu_driver_init) 13387755cec6SMarc Zyngier 13397755cec6SMarc Zyngier void arch_perf_update_userpage(struct perf_event *event, 13407755cec6SMarc Zyngier struct perf_event_mmap_page *userpg, u64 now) 13417755cec6SMarc Zyngier { 13427755cec6SMarc Zyngier struct clock_read_data *rd; 13437755cec6SMarc Zyngier unsigned int seq; 13447755cec6SMarc Zyngier u64 ns; 13457755cec6SMarc Zyngier 13467755cec6SMarc Zyngier userpg->cap_user_time = 0; 13477755cec6SMarc Zyngier userpg->cap_user_time_zero = 0; 13487755cec6SMarc Zyngier userpg->cap_user_time_short = 0; 13497755cec6SMarc Zyngier userpg->cap_user_rdpmc = armv8pmu_event_has_user_read(event); 13507755cec6SMarc Zyngier 13517755cec6SMarc Zyngier if (userpg->cap_user_rdpmc) { 13527755cec6SMarc Zyngier if (event->hw.flags & ARMPMU_EVT_64BIT) 13537755cec6SMarc Zyngier userpg->pmc_width = 64; 13547755cec6SMarc Zyngier else 13557755cec6SMarc Zyngier userpg->pmc_width = 32; 13567755cec6SMarc Zyngier } 13577755cec6SMarc Zyngier 13587755cec6SMarc Zyngier do { 13597755cec6SMarc Zyngier rd = sched_clock_read_begin(&seq); 13607755cec6SMarc Zyngier 13617755cec6SMarc Zyngier if (rd->read_sched_clock != arch_timer_read_counter) 13627755cec6SMarc Zyngier return; 13637755cec6SMarc Zyngier 13647755cec6SMarc Zyngier userpg->time_mult = rd->mult; 13657755cec6SMarc Zyngier userpg->time_shift = rd->shift; 13667755cec6SMarc Zyngier userpg->time_zero = rd->epoch_ns; 13677755cec6SMarc Zyngier userpg->time_cycles = rd->epoch_cyc; 13687755cec6SMarc Zyngier userpg->time_mask = rd->sched_clock_mask; 13697755cec6SMarc Zyngier 13707755cec6SMarc Zyngier /* 13717755cec6SMarc Zyngier * Subtract the cycle base, such that software that 13727755cec6SMarc Zyngier * doesn't know about cap_user_time_short still 'works' 13737755cec6SMarc Zyngier * assuming no wraps. 13747755cec6SMarc Zyngier */ 13757755cec6SMarc Zyngier ns = mul_u64_u32_shr(rd->epoch_cyc, rd->mult, rd->shift); 13767755cec6SMarc Zyngier userpg->time_zero -= ns; 13777755cec6SMarc Zyngier 13787755cec6SMarc Zyngier } while (sched_clock_read_retry(seq)); 13797755cec6SMarc Zyngier 13807755cec6SMarc Zyngier userpg->time_offset = userpg->time_zero - now; 13817755cec6SMarc Zyngier 13827755cec6SMarc Zyngier /* 13837755cec6SMarc Zyngier * time_shift is not expected to be greater than 31 due to 13847755cec6SMarc Zyngier * the original published conversion algorithm shifting a 13857755cec6SMarc Zyngier * 32-bit value (now specifies a 64-bit value) - refer 13867755cec6SMarc Zyngier * perf_event_mmap_page documentation in perf_event.h. 13877755cec6SMarc Zyngier */ 13887755cec6SMarc Zyngier if (userpg->time_shift == 32) { 13897755cec6SMarc Zyngier userpg->time_shift = 31; 13907755cec6SMarc Zyngier userpg->time_mult >>= 1; 13917755cec6SMarc Zyngier } 13927755cec6SMarc Zyngier 13937755cec6SMarc Zyngier /* 13947755cec6SMarc Zyngier * Internal timekeeping for enabled/running/stopped times 13957755cec6SMarc Zyngier * is always computed with the sched_clock. 13967755cec6SMarc Zyngier */ 13977755cec6SMarc Zyngier userpg->cap_user_time = 1; 13987755cec6SMarc Zyngier userpg->cap_user_time_zero = 1; 13997755cec6SMarc Zyngier userpg->cap_user_time_short = 1; 14007755cec6SMarc Zyngier } 1401