162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ARMv8 PMUv3 Performance Events handling code. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2012 ARM Limited 662306a36Sopenharmony_ci * Author: Will Deacon <will.deacon@arm.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This code is based heavily on the ARMv7 perf event code. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <asm/irq_regs.h> 1262306a36Sopenharmony_ci#include <asm/perf_event.h> 1362306a36Sopenharmony_ci#include <asm/virt.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <clocksource/arm_arch_timer.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/acpi.h> 1862306a36Sopenharmony_ci#include <linux/clocksource.h> 1962306a36Sopenharmony_ci#include <linux/of.h> 2062306a36Sopenharmony_ci#include <linux/perf/arm_pmu.h> 2162306a36Sopenharmony_ci#include <linux/perf/arm_pmuv3.h> 2262306a36Sopenharmony_ci#include <linux/platform_device.h> 2362306a36Sopenharmony_ci#include <linux/sched_clock.h> 2462306a36Sopenharmony_ci#include <linux/smp.h> 2562306a36Sopenharmony_ci#include <linux/nmi.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <asm/arm_pmuv3.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* ARMv8 Cortex-A53 specific event types. */ 3062306a36Sopenharmony_ci#define ARMV8_A53_PERFCTR_PREF_LINEFILL 0xC2 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* ARMv8 Cavium ThunderX specific event types. */ 3362306a36Sopenharmony_ci#define ARMV8_THUNDER_PERFCTR_L1D_CACHE_MISS_ST 0xE9 3462306a36Sopenharmony_ci#define ARMV8_THUNDER_PERFCTR_L1D_CACHE_PREF_ACCESS 0xEA 3562306a36Sopenharmony_ci#define ARMV8_THUNDER_PERFCTR_L1D_CACHE_PREF_MISS 0xEB 3662306a36Sopenharmony_ci#define ARMV8_THUNDER_PERFCTR_L1I_CACHE_PREF_ACCESS 0xEC 3762306a36Sopenharmony_ci#define ARMV8_THUNDER_PERFCTR_L1I_CACHE_PREF_MISS 0xED 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* 4062306a36Sopenharmony_ci * ARMv8 Architectural defined events, not all of these may 4162306a36Sopenharmony_ci * be supported on any given implementation. Unsupported events will 4262306a36Sopenharmony_ci * be disabled at run-time based on the PMCEID registers. 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_cistatic const unsigned armv8_pmuv3_perf_map[PERF_COUNT_HW_MAX] = { 4562306a36Sopenharmony_ci PERF_MAP_ALL_UNSUPPORTED, 4662306a36Sopenharmony_ci [PERF_COUNT_HW_CPU_CYCLES] = ARMV8_PMUV3_PERFCTR_CPU_CYCLES, 4762306a36Sopenharmony_ci [PERF_COUNT_HW_INSTRUCTIONS] = ARMV8_PMUV3_PERFCTR_INST_RETIRED, 4862306a36Sopenharmony_ci [PERF_COUNT_HW_CACHE_REFERENCES] = ARMV8_PMUV3_PERFCTR_L1D_CACHE, 4962306a36Sopenharmony_ci [PERF_COUNT_HW_CACHE_MISSES] = ARMV8_PMUV3_PERFCTR_L1D_CACHE_REFILL, 5062306a36Sopenharmony_ci [PERF_COUNT_HW_BRANCH_MISSES] = ARMV8_PMUV3_PERFCTR_BR_MIS_PRED, 5162306a36Sopenharmony_ci [PERF_COUNT_HW_BUS_CYCLES] = ARMV8_PMUV3_PERFCTR_BUS_CYCLES, 5262306a36Sopenharmony_ci [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = ARMV8_PMUV3_PERFCTR_STALL_FRONTEND, 5362306a36Sopenharmony_ci [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = ARMV8_PMUV3_PERFCTR_STALL_BACKEND, 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic const unsigned armv8_pmuv3_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] 5762306a36Sopenharmony_ci [PERF_COUNT_HW_CACHE_OP_MAX] 5862306a36Sopenharmony_ci [PERF_COUNT_HW_CACHE_RESULT_MAX] = { 5962306a36Sopenharmony_ci PERF_CACHE_MAP_ALL_UNSUPPORTED, 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_L1D_CACHE, 6262306a36Sopenharmony_ci [C(L1D)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_L1D_CACHE_REFILL, 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci [C(L1I)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_L1I_CACHE, 6562306a36Sopenharmony_ci [C(L1I)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_L1I_CACHE_REFILL, 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci [C(DTLB)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_L1D_TLB_REFILL, 6862306a36Sopenharmony_ci [C(DTLB)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_L1D_TLB, 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci [C(ITLB)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_L1I_TLB_REFILL, 7162306a36Sopenharmony_ci [C(ITLB)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_L1I_TLB, 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci [C(LL)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_LL_CACHE_MISS_RD, 7462306a36Sopenharmony_ci [C(LL)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_LL_CACHE_RD, 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci [C(BPU)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_BR_PRED, 7762306a36Sopenharmony_ci [C(BPU)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_BR_MIS_PRED, 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic const unsigned armv8_a53_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] 8162306a36Sopenharmony_ci [PERF_COUNT_HW_CACHE_OP_MAX] 8262306a36Sopenharmony_ci [PERF_COUNT_HW_CACHE_RESULT_MAX] = { 8362306a36Sopenharmony_ci PERF_CACHE_MAP_ALL_UNSUPPORTED, 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci [C(L1D)][C(OP_PREFETCH)][C(RESULT_MISS)] = ARMV8_A53_PERFCTR_PREF_LINEFILL, 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci [C(NODE)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_RD, 8862306a36Sopenharmony_ci [C(NODE)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_WR, 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic const unsigned armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] 9262306a36Sopenharmony_ci [PERF_COUNT_HW_CACHE_OP_MAX] 9362306a36Sopenharmony_ci [PERF_COUNT_HW_CACHE_RESULT_MAX] = { 9462306a36Sopenharmony_ci PERF_CACHE_MAP_ALL_UNSUPPORTED, 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_RD, 9762306a36Sopenharmony_ci [C(L1D)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_REFILL_RD, 9862306a36Sopenharmony_ci [C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_WR, 9962306a36Sopenharmony_ci [C(L1D)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_REFILL_WR, 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci [C(DTLB)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_REFILL_RD, 10262306a36Sopenharmony_ci [C(DTLB)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_REFILL_WR, 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci [C(NODE)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_RD, 10562306a36Sopenharmony_ci [C(NODE)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_WR, 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic const unsigned armv8_a73_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] 10962306a36Sopenharmony_ci [PERF_COUNT_HW_CACHE_OP_MAX] 11062306a36Sopenharmony_ci [PERF_COUNT_HW_CACHE_RESULT_MAX] = { 11162306a36Sopenharmony_ci PERF_CACHE_MAP_ALL_UNSUPPORTED, 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_RD, 11462306a36Sopenharmony_ci [C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_WR, 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic const unsigned armv8_thunder_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] 11862306a36Sopenharmony_ci [PERF_COUNT_HW_CACHE_OP_MAX] 11962306a36Sopenharmony_ci [PERF_COUNT_HW_CACHE_RESULT_MAX] = { 12062306a36Sopenharmony_ci PERF_CACHE_MAP_ALL_UNSUPPORTED, 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_RD, 12362306a36Sopenharmony_ci [C(L1D)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_REFILL_RD, 12462306a36Sopenharmony_ci [C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_WR, 12562306a36Sopenharmony_ci [C(L1D)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_THUNDER_PERFCTR_L1D_CACHE_MISS_ST, 12662306a36Sopenharmony_ci [C(L1D)][C(OP_PREFETCH)][C(RESULT_ACCESS)] = ARMV8_THUNDER_PERFCTR_L1D_CACHE_PREF_ACCESS, 12762306a36Sopenharmony_ci [C(L1D)][C(OP_PREFETCH)][C(RESULT_MISS)] = ARMV8_THUNDER_PERFCTR_L1D_CACHE_PREF_MISS, 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci [C(L1I)][C(OP_PREFETCH)][C(RESULT_ACCESS)] = ARMV8_THUNDER_PERFCTR_L1I_CACHE_PREF_ACCESS, 13062306a36Sopenharmony_ci [C(L1I)][C(OP_PREFETCH)][C(RESULT_MISS)] = ARMV8_THUNDER_PERFCTR_L1I_CACHE_PREF_MISS, 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci [C(DTLB)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_RD, 13362306a36Sopenharmony_ci [C(DTLB)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_REFILL_RD, 13462306a36Sopenharmony_ci [C(DTLB)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_WR, 13562306a36Sopenharmony_ci [C(DTLB)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_REFILL_WR, 13662306a36Sopenharmony_ci}; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic const unsigned armv8_vulcan_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] 13962306a36Sopenharmony_ci [PERF_COUNT_HW_CACHE_OP_MAX] 14062306a36Sopenharmony_ci [PERF_COUNT_HW_CACHE_RESULT_MAX] = { 14162306a36Sopenharmony_ci PERF_CACHE_MAP_ALL_UNSUPPORTED, 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_RD, 14462306a36Sopenharmony_ci [C(L1D)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_REFILL_RD, 14562306a36Sopenharmony_ci [C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_WR, 14662306a36Sopenharmony_ci [C(L1D)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_REFILL_WR, 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci [C(DTLB)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_RD, 14962306a36Sopenharmony_ci [C(DTLB)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_WR, 15062306a36Sopenharmony_ci [C(DTLB)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_REFILL_RD, 15162306a36Sopenharmony_ci [C(DTLB)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_REFILL_WR, 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci [C(NODE)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_RD, 15462306a36Sopenharmony_ci [C(NODE)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_WR, 15562306a36Sopenharmony_ci}; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic ssize_t 15862306a36Sopenharmony_ciarmv8pmu_events_sysfs_show(struct device *dev, 15962306a36Sopenharmony_ci struct device_attribute *attr, char *page) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci struct perf_pmu_events_attr *pmu_attr; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci return sprintf(page, "event=0x%04llx\n", pmu_attr->id); 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci#define ARMV8_EVENT_ATTR(name, config) \ 16962306a36Sopenharmony_ci PMU_EVENT_ATTR_ID(name, armv8pmu_events_sysfs_show, config) 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic struct attribute *armv8_pmuv3_event_attrs[] = { 17262306a36Sopenharmony_ci /* 17362306a36Sopenharmony_ci * Don't expose the sw_incr event in /sys. It's not usable as writes to 17462306a36Sopenharmony_ci * PMSWINC_EL0 will trap as PMUSERENR.{SW,EN}=={0,0} and event rotation 17562306a36Sopenharmony_ci * means we don't have a fixed event<->counter relationship regardless. 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l1i_cache_refill, ARMV8_PMUV3_PERFCTR_L1I_CACHE_REFILL), 17862306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l1i_tlb_refill, ARMV8_PMUV3_PERFCTR_L1I_TLB_REFILL), 17962306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l1d_cache_refill, ARMV8_PMUV3_PERFCTR_L1D_CACHE_REFILL), 18062306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l1d_cache, ARMV8_PMUV3_PERFCTR_L1D_CACHE), 18162306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l1d_tlb_refill, ARMV8_PMUV3_PERFCTR_L1D_TLB_REFILL), 18262306a36Sopenharmony_ci ARMV8_EVENT_ATTR(ld_retired, ARMV8_PMUV3_PERFCTR_LD_RETIRED), 18362306a36Sopenharmony_ci ARMV8_EVENT_ATTR(st_retired, ARMV8_PMUV3_PERFCTR_ST_RETIRED), 18462306a36Sopenharmony_ci ARMV8_EVENT_ATTR(inst_retired, ARMV8_PMUV3_PERFCTR_INST_RETIRED), 18562306a36Sopenharmony_ci ARMV8_EVENT_ATTR(exc_taken, ARMV8_PMUV3_PERFCTR_EXC_TAKEN), 18662306a36Sopenharmony_ci ARMV8_EVENT_ATTR(exc_return, ARMV8_PMUV3_PERFCTR_EXC_RETURN), 18762306a36Sopenharmony_ci ARMV8_EVENT_ATTR(cid_write_retired, ARMV8_PMUV3_PERFCTR_CID_WRITE_RETIRED), 18862306a36Sopenharmony_ci ARMV8_EVENT_ATTR(pc_write_retired, ARMV8_PMUV3_PERFCTR_PC_WRITE_RETIRED), 18962306a36Sopenharmony_ci ARMV8_EVENT_ATTR(br_immed_retired, ARMV8_PMUV3_PERFCTR_BR_IMMED_RETIRED), 19062306a36Sopenharmony_ci ARMV8_EVENT_ATTR(br_return_retired, ARMV8_PMUV3_PERFCTR_BR_RETURN_RETIRED), 19162306a36Sopenharmony_ci ARMV8_EVENT_ATTR(unaligned_ldst_retired, ARMV8_PMUV3_PERFCTR_UNALIGNED_LDST_RETIRED), 19262306a36Sopenharmony_ci ARMV8_EVENT_ATTR(br_mis_pred, ARMV8_PMUV3_PERFCTR_BR_MIS_PRED), 19362306a36Sopenharmony_ci ARMV8_EVENT_ATTR(cpu_cycles, ARMV8_PMUV3_PERFCTR_CPU_CYCLES), 19462306a36Sopenharmony_ci ARMV8_EVENT_ATTR(br_pred, ARMV8_PMUV3_PERFCTR_BR_PRED), 19562306a36Sopenharmony_ci ARMV8_EVENT_ATTR(mem_access, ARMV8_PMUV3_PERFCTR_MEM_ACCESS), 19662306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l1i_cache, ARMV8_PMUV3_PERFCTR_L1I_CACHE), 19762306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l1d_cache_wb, ARMV8_PMUV3_PERFCTR_L1D_CACHE_WB), 19862306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l2d_cache, ARMV8_PMUV3_PERFCTR_L2D_CACHE), 19962306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l2d_cache_refill, ARMV8_PMUV3_PERFCTR_L2D_CACHE_REFILL), 20062306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l2d_cache_wb, ARMV8_PMUV3_PERFCTR_L2D_CACHE_WB), 20162306a36Sopenharmony_ci ARMV8_EVENT_ATTR(bus_access, ARMV8_PMUV3_PERFCTR_BUS_ACCESS), 20262306a36Sopenharmony_ci ARMV8_EVENT_ATTR(memory_error, ARMV8_PMUV3_PERFCTR_MEMORY_ERROR), 20362306a36Sopenharmony_ci ARMV8_EVENT_ATTR(inst_spec, ARMV8_PMUV3_PERFCTR_INST_SPEC), 20462306a36Sopenharmony_ci ARMV8_EVENT_ATTR(ttbr_write_retired, ARMV8_PMUV3_PERFCTR_TTBR_WRITE_RETIRED), 20562306a36Sopenharmony_ci ARMV8_EVENT_ATTR(bus_cycles, ARMV8_PMUV3_PERFCTR_BUS_CYCLES), 20662306a36Sopenharmony_ci /* Don't expose the chain event in /sys, since it's useless in isolation */ 20762306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l1d_cache_allocate, ARMV8_PMUV3_PERFCTR_L1D_CACHE_ALLOCATE), 20862306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l2d_cache_allocate, ARMV8_PMUV3_PERFCTR_L2D_CACHE_ALLOCATE), 20962306a36Sopenharmony_ci ARMV8_EVENT_ATTR(br_retired, ARMV8_PMUV3_PERFCTR_BR_RETIRED), 21062306a36Sopenharmony_ci ARMV8_EVENT_ATTR(br_mis_pred_retired, ARMV8_PMUV3_PERFCTR_BR_MIS_PRED_RETIRED), 21162306a36Sopenharmony_ci ARMV8_EVENT_ATTR(stall_frontend, ARMV8_PMUV3_PERFCTR_STALL_FRONTEND), 21262306a36Sopenharmony_ci ARMV8_EVENT_ATTR(stall_backend, ARMV8_PMUV3_PERFCTR_STALL_BACKEND), 21362306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l1d_tlb, ARMV8_PMUV3_PERFCTR_L1D_TLB), 21462306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l1i_tlb, ARMV8_PMUV3_PERFCTR_L1I_TLB), 21562306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l2i_cache, ARMV8_PMUV3_PERFCTR_L2I_CACHE), 21662306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l2i_cache_refill, ARMV8_PMUV3_PERFCTR_L2I_CACHE_REFILL), 21762306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l3d_cache_allocate, ARMV8_PMUV3_PERFCTR_L3D_CACHE_ALLOCATE), 21862306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l3d_cache_refill, ARMV8_PMUV3_PERFCTR_L3D_CACHE_REFILL), 21962306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l3d_cache, ARMV8_PMUV3_PERFCTR_L3D_CACHE), 22062306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l3d_cache_wb, ARMV8_PMUV3_PERFCTR_L3D_CACHE_WB), 22162306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l2d_tlb_refill, ARMV8_PMUV3_PERFCTR_L2D_TLB_REFILL), 22262306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l2i_tlb_refill, ARMV8_PMUV3_PERFCTR_L2I_TLB_REFILL), 22362306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l2d_tlb, ARMV8_PMUV3_PERFCTR_L2D_TLB), 22462306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l2i_tlb, ARMV8_PMUV3_PERFCTR_L2I_TLB), 22562306a36Sopenharmony_ci ARMV8_EVENT_ATTR(remote_access, ARMV8_PMUV3_PERFCTR_REMOTE_ACCESS), 22662306a36Sopenharmony_ci ARMV8_EVENT_ATTR(ll_cache, ARMV8_PMUV3_PERFCTR_LL_CACHE), 22762306a36Sopenharmony_ci ARMV8_EVENT_ATTR(ll_cache_miss, ARMV8_PMUV3_PERFCTR_LL_CACHE_MISS), 22862306a36Sopenharmony_ci ARMV8_EVENT_ATTR(dtlb_walk, ARMV8_PMUV3_PERFCTR_DTLB_WALK), 22962306a36Sopenharmony_ci ARMV8_EVENT_ATTR(itlb_walk, ARMV8_PMUV3_PERFCTR_ITLB_WALK), 23062306a36Sopenharmony_ci ARMV8_EVENT_ATTR(ll_cache_rd, ARMV8_PMUV3_PERFCTR_LL_CACHE_RD), 23162306a36Sopenharmony_ci ARMV8_EVENT_ATTR(ll_cache_miss_rd, ARMV8_PMUV3_PERFCTR_LL_CACHE_MISS_RD), 23262306a36Sopenharmony_ci ARMV8_EVENT_ATTR(remote_access_rd, ARMV8_PMUV3_PERFCTR_REMOTE_ACCESS_RD), 23362306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l1d_cache_lmiss_rd, ARMV8_PMUV3_PERFCTR_L1D_CACHE_LMISS_RD), 23462306a36Sopenharmony_ci ARMV8_EVENT_ATTR(op_retired, ARMV8_PMUV3_PERFCTR_OP_RETIRED), 23562306a36Sopenharmony_ci ARMV8_EVENT_ATTR(op_spec, ARMV8_PMUV3_PERFCTR_OP_SPEC), 23662306a36Sopenharmony_ci ARMV8_EVENT_ATTR(stall, ARMV8_PMUV3_PERFCTR_STALL), 23762306a36Sopenharmony_ci ARMV8_EVENT_ATTR(stall_slot_backend, ARMV8_PMUV3_PERFCTR_STALL_SLOT_BACKEND), 23862306a36Sopenharmony_ci ARMV8_EVENT_ATTR(stall_slot_frontend, ARMV8_PMUV3_PERFCTR_STALL_SLOT_FRONTEND), 23962306a36Sopenharmony_ci ARMV8_EVENT_ATTR(stall_slot, ARMV8_PMUV3_PERFCTR_STALL_SLOT), 24062306a36Sopenharmony_ci ARMV8_EVENT_ATTR(sample_pop, ARMV8_SPE_PERFCTR_SAMPLE_POP), 24162306a36Sopenharmony_ci ARMV8_EVENT_ATTR(sample_feed, ARMV8_SPE_PERFCTR_SAMPLE_FEED), 24262306a36Sopenharmony_ci ARMV8_EVENT_ATTR(sample_filtrate, ARMV8_SPE_PERFCTR_SAMPLE_FILTRATE), 24362306a36Sopenharmony_ci ARMV8_EVENT_ATTR(sample_collision, ARMV8_SPE_PERFCTR_SAMPLE_COLLISION), 24462306a36Sopenharmony_ci ARMV8_EVENT_ATTR(cnt_cycles, ARMV8_AMU_PERFCTR_CNT_CYCLES), 24562306a36Sopenharmony_ci ARMV8_EVENT_ATTR(stall_backend_mem, ARMV8_AMU_PERFCTR_STALL_BACKEND_MEM), 24662306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l1i_cache_lmiss, ARMV8_PMUV3_PERFCTR_L1I_CACHE_LMISS), 24762306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l2d_cache_lmiss_rd, ARMV8_PMUV3_PERFCTR_L2D_CACHE_LMISS_RD), 24862306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l2i_cache_lmiss, ARMV8_PMUV3_PERFCTR_L2I_CACHE_LMISS), 24962306a36Sopenharmony_ci ARMV8_EVENT_ATTR(l3d_cache_lmiss_rd, ARMV8_PMUV3_PERFCTR_L3D_CACHE_LMISS_RD), 25062306a36Sopenharmony_ci ARMV8_EVENT_ATTR(trb_wrap, ARMV8_PMUV3_PERFCTR_TRB_WRAP), 25162306a36Sopenharmony_ci ARMV8_EVENT_ATTR(trb_trig, ARMV8_PMUV3_PERFCTR_TRB_TRIG), 25262306a36Sopenharmony_ci ARMV8_EVENT_ATTR(trcextout0, ARMV8_PMUV3_PERFCTR_TRCEXTOUT0), 25362306a36Sopenharmony_ci ARMV8_EVENT_ATTR(trcextout1, ARMV8_PMUV3_PERFCTR_TRCEXTOUT1), 25462306a36Sopenharmony_ci ARMV8_EVENT_ATTR(trcextout2, ARMV8_PMUV3_PERFCTR_TRCEXTOUT2), 25562306a36Sopenharmony_ci ARMV8_EVENT_ATTR(trcextout3, ARMV8_PMUV3_PERFCTR_TRCEXTOUT3), 25662306a36Sopenharmony_ci ARMV8_EVENT_ATTR(cti_trigout4, ARMV8_PMUV3_PERFCTR_CTI_TRIGOUT4), 25762306a36Sopenharmony_ci ARMV8_EVENT_ATTR(cti_trigout5, ARMV8_PMUV3_PERFCTR_CTI_TRIGOUT5), 25862306a36Sopenharmony_ci ARMV8_EVENT_ATTR(cti_trigout6, ARMV8_PMUV3_PERFCTR_CTI_TRIGOUT6), 25962306a36Sopenharmony_ci ARMV8_EVENT_ATTR(cti_trigout7, ARMV8_PMUV3_PERFCTR_CTI_TRIGOUT7), 26062306a36Sopenharmony_ci ARMV8_EVENT_ATTR(ldst_align_lat, ARMV8_PMUV3_PERFCTR_LDST_ALIGN_LAT), 26162306a36Sopenharmony_ci ARMV8_EVENT_ATTR(ld_align_lat, ARMV8_PMUV3_PERFCTR_LD_ALIGN_LAT), 26262306a36Sopenharmony_ci ARMV8_EVENT_ATTR(st_align_lat, ARMV8_PMUV3_PERFCTR_ST_ALIGN_LAT), 26362306a36Sopenharmony_ci ARMV8_EVENT_ATTR(mem_access_checked, ARMV8_MTE_PERFCTR_MEM_ACCESS_CHECKED), 26462306a36Sopenharmony_ci ARMV8_EVENT_ATTR(mem_access_checked_rd, ARMV8_MTE_PERFCTR_MEM_ACCESS_CHECKED_RD), 26562306a36Sopenharmony_ci ARMV8_EVENT_ATTR(mem_access_checked_wr, ARMV8_MTE_PERFCTR_MEM_ACCESS_CHECKED_WR), 26662306a36Sopenharmony_ci NULL, 26762306a36Sopenharmony_ci}; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic umode_t 27062306a36Sopenharmony_ciarmv8pmu_event_attr_is_visible(struct kobject *kobj, 27162306a36Sopenharmony_ci struct attribute *attr, int unused) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 27462306a36Sopenharmony_ci struct pmu *pmu = dev_get_drvdata(dev); 27562306a36Sopenharmony_ci struct arm_pmu *cpu_pmu = container_of(pmu, struct arm_pmu, pmu); 27662306a36Sopenharmony_ci struct perf_pmu_events_attr *pmu_attr; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr.attr); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (pmu_attr->id < ARMV8_PMUV3_MAX_COMMON_EVENTS && 28162306a36Sopenharmony_ci test_bit(pmu_attr->id, cpu_pmu->pmceid_bitmap)) 28262306a36Sopenharmony_ci return attr->mode; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (pmu_attr->id >= ARMV8_PMUV3_EXT_COMMON_EVENT_BASE) { 28562306a36Sopenharmony_ci u64 id = pmu_attr->id - ARMV8_PMUV3_EXT_COMMON_EVENT_BASE; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (id < ARMV8_PMUV3_MAX_COMMON_EVENTS && 28862306a36Sopenharmony_ci test_bit(id, cpu_pmu->pmceid_ext_bitmap)) 28962306a36Sopenharmony_ci return attr->mode; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return 0; 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic const struct attribute_group armv8_pmuv3_events_attr_group = { 29662306a36Sopenharmony_ci .name = "events", 29762306a36Sopenharmony_ci .attrs = armv8_pmuv3_event_attrs, 29862306a36Sopenharmony_ci .is_visible = armv8pmu_event_attr_is_visible, 29962306a36Sopenharmony_ci}; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ciPMU_FORMAT_ATTR(event, "config:0-15"); 30262306a36Sopenharmony_ciPMU_FORMAT_ATTR(long, "config1:0"); 30362306a36Sopenharmony_ciPMU_FORMAT_ATTR(rdpmc, "config1:1"); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic int sysctl_perf_user_access __read_mostly; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic inline bool armv8pmu_event_is_64bit(struct perf_event *event) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci return event->attr.config1 & 0x1; 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic inline bool armv8pmu_event_want_user_access(struct perf_event *event) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci return event->attr.config1 & 0x2; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic struct attribute *armv8_pmuv3_format_attrs[] = { 31862306a36Sopenharmony_ci &format_attr_event.attr, 31962306a36Sopenharmony_ci &format_attr_long.attr, 32062306a36Sopenharmony_ci &format_attr_rdpmc.attr, 32162306a36Sopenharmony_ci NULL, 32262306a36Sopenharmony_ci}; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic const struct attribute_group armv8_pmuv3_format_attr_group = { 32562306a36Sopenharmony_ci .name = "format", 32662306a36Sopenharmony_ci .attrs = armv8_pmuv3_format_attrs, 32762306a36Sopenharmony_ci}; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic ssize_t slots_show(struct device *dev, struct device_attribute *attr, 33062306a36Sopenharmony_ci char *page) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci struct pmu *pmu = dev_get_drvdata(dev); 33362306a36Sopenharmony_ci struct arm_pmu *cpu_pmu = container_of(pmu, struct arm_pmu, pmu); 33462306a36Sopenharmony_ci u32 slots = cpu_pmu->reg_pmmir & ARMV8_PMU_SLOTS_MASK; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci return sysfs_emit(page, "0x%08x\n", slots); 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(slots); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic ssize_t bus_slots_show(struct device *dev, struct device_attribute *attr, 34262306a36Sopenharmony_ci char *page) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci struct pmu *pmu = dev_get_drvdata(dev); 34562306a36Sopenharmony_ci struct arm_pmu *cpu_pmu = container_of(pmu, struct arm_pmu, pmu); 34662306a36Sopenharmony_ci u32 bus_slots = (cpu_pmu->reg_pmmir >> ARMV8_PMU_BUS_SLOTS_SHIFT) 34762306a36Sopenharmony_ci & ARMV8_PMU_BUS_SLOTS_MASK; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci return sysfs_emit(page, "0x%08x\n", bus_slots); 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(bus_slots); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic ssize_t bus_width_show(struct device *dev, struct device_attribute *attr, 35562306a36Sopenharmony_ci char *page) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci struct pmu *pmu = dev_get_drvdata(dev); 35862306a36Sopenharmony_ci struct arm_pmu *cpu_pmu = container_of(pmu, struct arm_pmu, pmu); 35962306a36Sopenharmony_ci u32 bus_width = (cpu_pmu->reg_pmmir >> ARMV8_PMU_BUS_WIDTH_SHIFT) 36062306a36Sopenharmony_ci & ARMV8_PMU_BUS_WIDTH_MASK; 36162306a36Sopenharmony_ci u32 val = 0; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* Encoded as Log2(number of bytes), plus one */ 36462306a36Sopenharmony_ci if (bus_width > 2 && bus_width < 13) 36562306a36Sopenharmony_ci val = 1 << (bus_width - 1); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci return sysfs_emit(page, "0x%08x\n", val); 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(bus_width); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic struct attribute *armv8_pmuv3_caps_attrs[] = { 37362306a36Sopenharmony_ci &dev_attr_slots.attr, 37462306a36Sopenharmony_ci &dev_attr_bus_slots.attr, 37562306a36Sopenharmony_ci &dev_attr_bus_width.attr, 37662306a36Sopenharmony_ci NULL, 37762306a36Sopenharmony_ci}; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic const struct attribute_group armv8_pmuv3_caps_attr_group = { 38062306a36Sopenharmony_ci .name = "caps", 38162306a36Sopenharmony_ci .attrs = armv8_pmuv3_caps_attrs, 38262306a36Sopenharmony_ci}; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci/* 38562306a36Sopenharmony_ci * Perf Events' indices 38662306a36Sopenharmony_ci */ 38762306a36Sopenharmony_ci#define ARMV8_IDX_CYCLE_COUNTER 0 38862306a36Sopenharmony_ci#define ARMV8_IDX_COUNTER0 1 38962306a36Sopenharmony_ci#define ARMV8_IDX_CYCLE_COUNTER_USER 32 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci/* 39262306a36Sopenharmony_ci * We unconditionally enable ARMv8.5-PMU long event counter support 39362306a36Sopenharmony_ci * (64-bit events) where supported. Indicate if this arm_pmu has long 39462306a36Sopenharmony_ci * event counter support. 39562306a36Sopenharmony_ci * 39662306a36Sopenharmony_ci * On AArch32, long counters make no sense (you can't access the top 39762306a36Sopenharmony_ci * bits), so we only enable this on AArch64. 39862306a36Sopenharmony_ci */ 39962306a36Sopenharmony_cistatic bool armv8pmu_has_long_event(struct arm_pmu *cpu_pmu) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci return (IS_ENABLED(CONFIG_ARM64) && is_pmuv3p5(cpu_pmu->pmuver)); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic inline bool armv8pmu_event_has_user_read(struct perf_event *event) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci return event->hw.flags & PERF_EVENT_FLAG_USER_READ_CNT; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci/* 41062306a36Sopenharmony_ci * We must chain two programmable counters for 64 bit events, 41162306a36Sopenharmony_ci * except when we have allocated the 64bit cycle counter (for CPU 41262306a36Sopenharmony_ci * cycles event) or when user space counter access is enabled. 41362306a36Sopenharmony_ci */ 41462306a36Sopenharmony_cistatic inline bool armv8pmu_event_is_chained(struct perf_event *event) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci int idx = event->hw.idx; 41762306a36Sopenharmony_ci struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci return !armv8pmu_event_has_user_read(event) && 42062306a36Sopenharmony_ci armv8pmu_event_is_64bit(event) && 42162306a36Sopenharmony_ci !armv8pmu_has_long_event(cpu_pmu) && 42262306a36Sopenharmony_ci (idx != ARMV8_IDX_CYCLE_COUNTER); 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci/* 42662306a36Sopenharmony_ci * ARMv8 low level PMU access 42762306a36Sopenharmony_ci */ 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci/* 43062306a36Sopenharmony_ci * Perf Event to low level counters mapping 43162306a36Sopenharmony_ci */ 43262306a36Sopenharmony_ci#define ARMV8_IDX_TO_COUNTER(x) \ 43362306a36Sopenharmony_ci (((x) - ARMV8_IDX_COUNTER0) & ARMV8_PMU_COUNTER_MASK) 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cistatic inline u64 armv8pmu_pmcr_read(void) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci return read_pmcr(); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic inline void armv8pmu_pmcr_write(u64 val) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci val &= ARMV8_PMU_PMCR_MASK; 44362306a36Sopenharmony_ci isb(); 44462306a36Sopenharmony_ci write_pmcr(val); 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic inline int armv8pmu_has_overflowed(u32 pmovsr) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci return pmovsr & ARMV8_PMU_OVERFLOWED_MASK; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic inline int armv8pmu_counter_has_overflowed(u32 pmnc, int idx) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci return pmnc & BIT(ARMV8_IDX_TO_COUNTER(idx)); 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic inline u64 armv8pmu_read_evcntr(int idx) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci u32 counter = ARMV8_IDX_TO_COUNTER(idx); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci return read_pmevcntrn(counter); 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic inline u64 armv8pmu_read_hw_counter(struct perf_event *event) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci int idx = event->hw.idx; 46762306a36Sopenharmony_ci u64 val = armv8pmu_read_evcntr(idx); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (armv8pmu_event_is_chained(event)) 47062306a36Sopenharmony_ci val = (val << 32) | armv8pmu_read_evcntr(idx - 1); 47162306a36Sopenharmony_ci return val; 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci/* 47562306a36Sopenharmony_ci * The cycle counter is always a 64-bit counter. When ARMV8_PMU_PMCR_LP 47662306a36Sopenharmony_ci * is set the event counters also become 64-bit counters. Unless the 47762306a36Sopenharmony_ci * user has requested a long counter (attr.config1) then we want to 47862306a36Sopenharmony_ci * interrupt upon 32-bit overflow - we achieve this by applying a bias. 47962306a36Sopenharmony_ci */ 48062306a36Sopenharmony_cistatic bool armv8pmu_event_needs_bias(struct perf_event *event) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); 48362306a36Sopenharmony_ci struct hw_perf_event *hwc = &event->hw; 48462306a36Sopenharmony_ci int idx = hwc->idx; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (armv8pmu_event_is_64bit(event)) 48762306a36Sopenharmony_ci return false; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (armv8pmu_has_long_event(cpu_pmu) || 49062306a36Sopenharmony_ci idx == ARMV8_IDX_CYCLE_COUNTER) 49162306a36Sopenharmony_ci return true; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci return false; 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_cistatic u64 armv8pmu_bias_long_counter(struct perf_event *event, u64 value) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci if (armv8pmu_event_needs_bias(event)) 49962306a36Sopenharmony_ci value |= GENMASK_ULL(63, 32); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci return value; 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic u64 armv8pmu_unbias_long_counter(struct perf_event *event, u64 value) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci if (armv8pmu_event_needs_bias(event)) 50762306a36Sopenharmony_ci value &= ~GENMASK_ULL(63, 32); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci return value; 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic u64 armv8pmu_read_counter(struct perf_event *event) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci struct hw_perf_event *hwc = &event->hw; 51562306a36Sopenharmony_ci int idx = hwc->idx; 51662306a36Sopenharmony_ci u64 value; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (idx == ARMV8_IDX_CYCLE_COUNTER) 51962306a36Sopenharmony_ci value = read_pmccntr(); 52062306a36Sopenharmony_ci else 52162306a36Sopenharmony_ci value = armv8pmu_read_hw_counter(event); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci return armv8pmu_unbias_long_counter(event, value); 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic inline void armv8pmu_write_evcntr(int idx, u64 value) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci u32 counter = ARMV8_IDX_TO_COUNTER(idx); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci write_pmevcntrn(counter, value); 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic inline void armv8pmu_write_hw_counter(struct perf_event *event, 53462306a36Sopenharmony_ci u64 value) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci int idx = event->hw.idx; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci if (armv8pmu_event_is_chained(event)) { 53962306a36Sopenharmony_ci armv8pmu_write_evcntr(idx, upper_32_bits(value)); 54062306a36Sopenharmony_ci armv8pmu_write_evcntr(idx - 1, lower_32_bits(value)); 54162306a36Sopenharmony_ci } else { 54262306a36Sopenharmony_ci armv8pmu_write_evcntr(idx, value); 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_cistatic void armv8pmu_write_counter(struct perf_event *event, u64 value) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci struct hw_perf_event *hwc = &event->hw; 54962306a36Sopenharmony_ci int idx = hwc->idx; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci value = armv8pmu_bias_long_counter(event, value); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci if (idx == ARMV8_IDX_CYCLE_COUNTER) 55462306a36Sopenharmony_ci write_pmccntr(value); 55562306a36Sopenharmony_ci else 55662306a36Sopenharmony_ci armv8pmu_write_hw_counter(event, value); 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_cistatic inline void armv8pmu_write_evtype(int idx, u32 val) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci u32 counter = ARMV8_IDX_TO_COUNTER(idx); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci val &= ARMV8_PMU_EVTYPE_MASK; 56462306a36Sopenharmony_ci write_pmevtypern(counter, val); 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_cistatic inline void armv8pmu_write_event_type(struct perf_event *event) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci struct hw_perf_event *hwc = &event->hw; 57062306a36Sopenharmony_ci int idx = hwc->idx; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* 57362306a36Sopenharmony_ci * For chained events, the low counter is programmed to count 57462306a36Sopenharmony_ci * the event of interest and the high counter is programmed 57562306a36Sopenharmony_ci * with CHAIN event code with filters set to count at all ELs. 57662306a36Sopenharmony_ci */ 57762306a36Sopenharmony_ci if (armv8pmu_event_is_chained(event)) { 57862306a36Sopenharmony_ci u32 chain_evt = ARMV8_PMUV3_PERFCTR_CHAIN | 57962306a36Sopenharmony_ci ARMV8_PMU_INCLUDE_EL2; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci armv8pmu_write_evtype(idx - 1, hwc->config_base); 58262306a36Sopenharmony_ci armv8pmu_write_evtype(idx, chain_evt); 58362306a36Sopenharmony_ci } else { 58462306a36Sopenharmony_ci if (idx == ARMV8_IDX_CYCLE_COUNTER) 58562306a36Sopenharmony_ci write_pmccfiltr(hwc->config_base); 58662306a36Sopenharmony_ci else 58762306a36Sopenharmony_ci armv8pmu_write_evtype(idx, hwc->config_base); 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic u32 armv8pmu_event_cnten_mask(struct perf_event *event) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci int counter = ARMV8_IDX_TO_COUNTER(event->hw.idx); 59462306a36Sopenharmony_ci u32 mask = BIT(counter); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (armv8pmu_event_is_chained(event)) 59762306a36Sopenharmony_ci mask |= BIT(counter - 1); 59862306a36Sopenharmony_ci return mask; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic inline void armv8pmu_enable_counter(u32 mask) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci /* 60462306a36Sopenharmony_ci * Make sure event configuration register writes are visible before we 60562306a36Sopenharmony_ci * enable the counter. 60662306a36Sopenharmony_ci * */ 60762306a36Sopenharmony_ci isb(); 60862306a36Sopenharmony_ci write_pmcntenset(mask); 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_cistatic inline void armv8pmu_enable_event_counter(struct perf_event *event) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci struct perf_event_attr *attr = &event->attr; 61462306a36Sopenharmony_ci u32 mask = armv8pmu_event_cnten_mask(event); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci kvm_set_pmu_events(mask, attr); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci /* We rely on the hypervisor switch code to enable guest counters */ 61962306a36Sopenharmony_ci if (!kvm_pmu_counter_deferred(attr)) 62062306a36Sopenharmony_ci armv8pmu_enable_counter(mask); 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistatic inline void armv8pmu_disable_counter(u32 mask) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci write_pmcntenclr(mask); 62662306a36Sopenharmony_ci /* 62762306a36Sopenharmony_ci * Make sure the effects of disabling the counter are visible before we 62862306a36Sopenharmony_ci * start configuring the event. 62962306a36Sopenharmony_ci */ 63062306a36Sopenharmony_ci isb(); 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cistatic inline void armv8pmu_disable_event_counter(struct perf_event *event) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci struct perf_event_attr *attr = &event->attr; 63662306a36Sopenharmony_ci u32 mask = armv8pmu_event_cnten_mask(event); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci kvm_clr_pmu_events(mask); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* We rely on the hypervisor switch code to disable guest counters */ 64162306a36Sopenharmony_ci if (!kvm_pmu_counter_deferred(attr)) 64262306a36Sopenharmony_ci armv8pmu_disable_counter(mask); 64362306a36Sopenharmony_ci} 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_cistatic inline void armv8pmu_enable_intens(u32 mask) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci write_pmintenset(mask); 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cistatic inline void armv8pmu_enable_event_irq(struct perf_event *event) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci u32 counter = ARMV8_IDX_TO_COUNTER(event->hw.idx); 65362306a36Sopenharmony_ci armv8pmu_enable_intens(BIT(counter)); 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic inline void armv8pmu_disable_intens(u32 mask) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci write_pmintenclr(mask); 65962306a36Sopenharmony_ci isb(); 66062306a36Sopenharmony_ci /* Clear the overflow flag in case an interrupt is pending. */ 66162306a36Sopenharmony_ci write_pmovsclr(mask); 66262306a36Sopenharmony_ci isb(); 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cistatic inline void armv8pmu_disable_event_irq(struct perf_event *event) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci u32 counter = ARMV8_IDX_TO_COUNTER(event->hw.idx); 66862306a36Sopenharmony_ci armv8pmu_disable_intens(BIT(counter)); 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistatic inline u32 armv8pmu_getreset_flags(void) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci u32 value; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* Read */ 67662306a36Sopenharmony_ci value = read_pmovsclr(); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci /* Write to clear flags */ 67962306a36Sopenharmony_ci value &= ARMV8_PMU_OVSR_MASK; 68062306a36Sopenharmony_ci write_pmovsclr(value); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci return value; 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic void update_pmuserenr(u64 val) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci lockdep_assert_irqs_disabled(); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci /* 69062306a36Sopenharmony_ci * The current PMUSERENR_EL0 value might be the value for the guest. 69162306a36Sopenharmony_ci * If that's the case, have KVM keep tracking of the register value 69262306a36Sopenharmony_ci * for the host EL0 so that KVM can restore it before returning to 69362306a36Sopenharmony_ci * the host EL0. Otherwise, update the register now. 69462306a36Sopenharmony_ci */ 69562306a36Sopenharmony_ci if (kvm_set_pmuserenr(val)) 69662306a36Sopenharmony_ci return; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci write_pmuserenr(val); 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_cistatic void armv8pmu_disable_user_access(void) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci update_pmuserenr(0); 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic void armv8pmu_enable_user_access(struct arm_pmu *cpu_pmu) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci int i; 70962306a36Sopenharmony_ci struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci /* Clear any unused counters to avoid leaking their contents */ 71262306a36Sopenharmony_ci for_each_clear_bit(i, cpuc->used_mask, cpu_pmu->num_events) { 71362306a36Sopenharmony_ci if (i == ARMV8_IDX_CYCLE_COUNTER) 71462306a36Sopenharmony_ci write_pmccntr(0); 71562306a36Sopenharmony_ci else 71662306a36Sopenharmony_ci armv8pmu_write_evcntr(i, 0); 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci update_pmuserenr(ARMV8_PMU_USERENR_ER | ARMV8_PMU_USERENR_CR); 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_cistatic void armv8pmu_enable_event(struct perf_event *event) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci /* 72562306a36Sopenharmony_ci * Enable counter and interrupt, and set the counter to count 72662306a36Sopenharmony_ci * the event that we're interested in. 72762306a36Sopenharmony_ci */ 72862306a36Sopenharmony_ci armv8pmu_disable_event_counter(event); 72962306a36Sopenharmony_ci armv8pmu_write_event_type(event); 73062306a36Sopenharmony_ci armv8pmu_enable_event_irq(event); 73162306a36Sopenharmony_ci armv8pmu_enable_event_counter(event); 73262306a36Sopenharmony_ci} 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_cistatic void armv8pmu_disable_event(struct perf_event *event) 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci armv8pmu_disable_event_counter(event); 73762306a36Sopenharmony_ci armv8pmu_disable_event_irq(event); 73862306a36Sopenharmony_ci} 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistatic void armv8pmu_start(struct arm_pmu *cpu_pmu) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci struct perf_event_context *ctx; 74362306a36Sopenharmony_ci int nr_user = 0; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci ctx = perf_cpu_task_ctx(); 74662306a36Sopenharmony_ci if (ctx) 74762306a36Sopenharmony_ci nr_user = ctx->nr_user; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci if (sysctl_perf_user_access && nr_user) 75062306a36Sopenharmony_ci armv8pmu_enable_user_access(cpu_pmu); 75162306a36Sopenharmony_ci else 75262306a36Sopenharmony_ci armv8pmu_disable_user_access(); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci /* Enable all counters */ 75562306a36Sopenharmony_ci armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMU_PMCR_E); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci kvm_vcpu_pmu_resync_el0(); 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic void armv8pmu_stop(struct arm_pmu *cpu_pmu) 76162306a36Sopenharmony_ci{ 76262306a36Sopenharmony_ci /* Disable all counters */ 76362306a36Sopenharmony_ci armv8pmu_pmcr_write(armv8pmu_pmcr_read() & ~ARMV8_PMU_PMCR_E); 76462306a36Sopenharmony_ci} 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_cistatic irqreturn_t armv8pmu_handle_irq(struct arm_pmu *cpu_pmu) 76762306a36Sopenharmony_ci{ 76862306a36Sopenharmony_ci u32 pmovsr; 76962306a36Sopenharmony_ci struct perf_sample_data data; 77062306a36Sopenharmony_ci struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events); 77162306a36Sopenharmony_ci struct pt_regs *regs; 77262306a36Sopenharmony_ci int idx; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci /* 77562306a36Sopenharmony_ci * Get and reset the IRQ flags 77662306a36Sopenharmony_ci */ 77762306a36Sopenharmony_ci pmovsr = armv8pmu_getreset_flags(); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci /* 78062306a36Sopenharmony_ci * Did an overflow occur? 78162306a36Sopenharmony_ci */ 78262306a36Sopenharmony_ci if (!armv8pmu_has_overflowed(pmovsr)) 78362306a36Sopenharmony_ci return IRQ_NONE; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci /* 78662306a36Sopenharmony_ci * Handle the counter(s) overflow(s) 78762306a36Sopenharmony_ci */ 78862306a36Sopenharmony_ci regs = get_irq_regs(); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci /* 79162306a36Sopenharmony_ci * Stop the PMU while processing the counter overflows 79262306a36Sopenharmony_ci * to prevent skews in group events. 79362306a36Sopenharmony_ci */ 79462306a36Sopenharmony_ci armv8pmu_stop(cpu_pmu); 79562306a36Sopenharmony_ci for (idx = 0; idx < cpu_pmu->num_events; ++idx) { 79662306a36Sopenharmony_ci struct perf_event *event = cpuc->events[idx]; 79762306a36Sopenharmony_ci struct hw_perf_event *hwc; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci /* Ignore if we don't have an event. */ 80062306a36Sopenharmony_ci if (!event) 80162306a36Sopenharmony_ci continue; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci /* 80462306a36Sopenharmony_ci * We have a single interrupt for all counters. Check that 80562306a36Sopenharmony_ci * each counter has overflowed before we process it. 80662306a36Sopenharmony_ci */ 80762306a36Sopenharmony_ci if (!armv8pmu_counter_has_overflowed(pmovsr, idx)) 80862306a36Sopenharmony_ci continue; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci hwc = &event->hw; 81162306a36Sopenharmony_ci armpmu_event_update(event); 81262306a36Sopenharmony_ci perf_sample_data_init(&data, 0, hwc->last_period); 81362306a36Sopenharmony_ci if (!armpmu_event_set_period(event)) 81462306a36Sopenharmony_ci continue; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci /* 81762306a36Sopenharmony_ci * Perf event overflow will queue the processing of the event as 81862306a36Sopenharmony_ci * an irq_work which will be taken care of in the handling of 81962306a36Sopenharmony_ci * IPI_IRQ_WORK. 82062306a36Sopenharmony_ci */ 82162306a36Sopenharmony_ci if (perf_event_overflow(event, &data, regs)) 82262306a36Sopenharmony_ci cpu_pmu->disable(event); 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci armv8pmu_start(cpu_pmu); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci return IRQ_HANDLED; 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_cistatic int armv8pmu_get_single_idx(struct pmu_hw_events *cpuc, 83062306a36Sopenharmony_ci struct arm_pmu *cpu_pmu) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci int idx; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci for (idx = ARMV8_IDX_COUNTER0; idx < cpu_pmu->num_events; idx++) { 83562306a36Sopenharmony_ci if (!test_and_set_bit(idx, cpuc->used_mask)) 83662306a36Sopenharmony_ci return idx; 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci return -EAGAIN; 83962306a36Sopenharmony_ci} 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_cistatic int armv8pmu_get_chain_idx(struct pmu_hw_events *cpuc, 84262306a36Sopenharmony_ci struct arm_pmu *cpu_pmu) 84362306a36Sopenharmony_ci{ 84462306a36Sopenharmony_ci int idx; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci /* 84762306a36Sopenharmony_ci * Chaining requires two consecutive event counters, where 84862306a36Sopenharmony_ci * the lower idx must be even. 84962306a36Sopenharmony_ci */ 85062306a36Sopenharmony_ci for (idx = ARMV8_IDX_COUNTER0 + 1; idx < cpu_pmu->num_events; idx += 2) { 85162306a36Sopenharmony_ci if (!test_and_set_bit(idx, cpuc->used_mask)) { 85262306a36Sopenharmony_ci /* Check if the preceding even counter is available */ 85362306a36Sopenharmony_ci if (!test_and_set_bit(idx - 1, cpuc->used_mask)) 85462306a36Sopenharmony_ci return idx; 85562306a36Sopenharmony_ci /* Release the Odd counter */ 85662306a36Sopenharmony_ci clear_bit(idx, cpuc->used_mask); 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci return -EAGAIN; 86062306a36Sopenharmony_ci} 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_cistatic int armv8pmu_get_event_idx(struct pmu_hw_events *cpuc, 86362306a36Sopenharmony_ci struct perf_event *event) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); 86662306a36Sopenharmony_ci struct hw_perf_event *hwc = &event->hw; 86762306a36Sopenharmony_ci unsigned long evtype = hwc->config_base & ARMV8_PMU_EVTYPE_EVENT; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci /* Always prefer to place a cycle counter into the cycle counter. */ 87062306a36Sopenharmony_ci if (evtype == ARMV8_PMUV3_PERFCTR_CPU_CYCLES) { 87162306a36Sopenharmony_ci if (!test_and_set_bit(ARMV8_IDX_CYCLE_COUNTER, cpuc->used_mask)) 87262306a36Sopenharmony_ci return ARMV8_IDX_CYCLE_COUNTER; 87362306a36Sopenharmony_ci else if (armv8pmu_event_is_64bit(event) && 87462306a36Sopenharmony_ci armv8pmu_event_want_user_access(event) && 87562306a36Sopenharmony_ci !armv8pmu_has_long_event(cpu_pmu)) 87662306a36Sopenharmony_ci return -EAGAIN; 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci /* 88062306a36Sopenharmony_ci * Otherwise use events counters 88162306a36Sopenharmony_ci */ 88262306a36Sopenharmony_ci if (armv8pmu_event_is_chained(event)) 88362306a36Sopenharmony_ci return armv8pmu_get_chain_idx(cpuc, cpu_pmu); 88462306a36Sopenharmony_ci else 88562306a36Sopenharmony_ci return armv8pmu_get_single_idx(cpuc, cpu_pmu); 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_cistatic void armv8pmu_clear_event_idx(struct pmu_hw_events *cpuc, 88962306a36Sopenharmony_ci struct perf_event *event) 89062306a36Sopenharmony_ci{ 89162306a36Sopenharmony_ci int idx = event->hw.idx; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci clear_bit(idx, cpuc->used_mask); 89462306a36Sopenharmony_ci if (armv8pmu_event_is_chained(event)) 89562306a36Sopenharmony_ci clear_bit(idx - 1, cpuc->used_mask); 89662306a36Sopenharmony_ci} 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cistatic int armv8pmu_user_event_idx(struct perf_event *event) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci if (!sysctl_perf_user_access || !armv8pmu_event_has_user_read(event)) 90162306a36Sopenharmony_ci return 0; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci /* 90462306a36Sopenharmony_ci * We remap the cycle counter index to 32 to 90562306a36Sopenharmony_ci * match the offset applied to the rest of 90662306a36Sopenharmony_ci * the counter indices. 90762306a36Sopenharmony_ci */ 90862306a36Sopenharmony_ci if (event->hw.idx == ARMV8_IDX_CYCLE_COUNTER) 90962306a36Sopenharmony_ci return ARMV8_IDX_CYCLE_COUNTER_USER; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci return event->hw.idx; 91262306a36Sopenharmony_ci} 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci/* 91562306a36Sopenharmony_ci * Add an event filter to a given event. 91662306a36Sopenharmony_ci */ 91762306a36Sopenharmony_cistatic int armv8pmu_set_event_filter(struct hw_perf_event *event, 91862306a36Sopenharmony_ci struct perf_event_attr *attr) 91962306a36Sopenharmony_ci{ 92062306a36Sopenharmony_ci unsigned long config_base = 0; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci if (attr->exclude_idle) 92362306a36Sopenharmony_ci return -EPERM; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci /* 92662306a36Sopenharmony_ci * If we're running in hyp mode, then we *are* the hypervisor. 92762306a36Sopenharmony_ci * Therefore we ignore exclude_hv in this configuration, since 92862306a36Sopenharmony_ci * there's no hypervisor to sample anyway. This is consistent 92962306a36Sopenharmony_ci * with other architectures (x86 and Power). 93062306a36Sopenharmony_ci */ 93162306a36Sopenharmony_ci if (is_kernel_in_hyp_mode()) { 93262306a36Sopenharmony_ci if (!attr->exclude_kernel && !attr->exclude_host) 93362306a36Sopenharmony_ci config_base |= ARMV8_PMU_INCLUDE_EL2; 93462306a36Sopenharmony_ci if (attr->exclude_guest) 93562306a36Sopenharmony_ci config_base |= ARMV8_PMU_EXCLUDE_EL1; 93662306a36Sopenharmony_ci if (attr->exclude_host) 93762306a36Sopenharmony_ci config_base |= ARMV8_PMU_EXCLUDE_EL0; 93862306a36Sopenharmony_ci } else { 93962306a36Sopenharmony_ci if (!attr->exclude_hv && !attr->exclude_host) 94062306a36Sopenharmony_ci config_base |= ARMV8_PMU_INCLUDE_EL2; 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci /* 94462306a36Sopenharmony_ci * Filter out !VHE kernels and guest kernels 94562306a36Sopenharmony_ci */ 94662306a36Sopenharmony_ci if (attr->exclude_kernel) 94762306a36Sopenharmony_ci config_base |= ARMV8_PMU_EXCLUDE_EL1; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci if (attr->exclude_user) 95062306a36Sopenharmony_ci config_base |= ARMV8_PMU_EXCLUDE_EL0; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci /* 95362306a36Sopenharmony_ci * Install the filter into config_base as this is used to 95462306a36Sopenharmony_ci * construct the event type. 95562306a36Sopenharmony_ci */ 95662306a36Sopenharmony_ci event->config_base = config_base; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci return 0; 95962306a36Sopenharmony_ci} 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_cistatic void armv8pmu_reset(void *info) 96262306a36Sopenharmony_ci{ 96362306a36Sopenharmony_ci struct arm_pmu *cpu_pmu = (struct arm_pmu *)info; 96462306a36Sopenharmony_ci u64 pmcr; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci /* The counter and interrupt enable registers are unknown at reset. */ 96762306a36Sopenharmony_ci armv8pmu_disable_counter(U32_MAX); 96862306a36Sopenharmony_ci armv8pmu_disable_intens(U32_MAX); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci /* Clear the counters we flip at guest entry/exit */ 97162306a36Sopenharmony_ci kvm_clr_pmu_events(U32_MAX); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci /* 97462306a36Sopenharmony_ci * Initialize & Reset PMNC. Request overflow interrupt for 97562306a36Sopenharmony_ci * 64 bit cycle counter but cheat in armv8pmu_write_counter(). 97662306a36Sopenharmony_ci */ 97762306a36Sopenharmony_ci pmcr = ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C | ARMV8_PMU_PMCR_LC; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci /* Enable long event counter support where available */ 98062306a36Sopenharmony_ci if (armv8pmu_has_long_event(cpu_pmu)) 98162306a36Sopenharmony_ci pmcr |= ARMV8_PMU_PMCR_LP; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci armv8pmu_pmcr_write(pmcr); 98462306a36Sopenharmony_ci} 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_cistatic int __armv8_pmuv3_map_event_id(struct arm_pmu *armpmu, 98762306a36Sopenharmony_ci struct perf_event *event) 98862306a36Sopenharmony_ci{ 98962306a36Sopenharmony_ci if (event->attr.type == PERF_TYPE_HARDWARE && 99062306a36Sopenharmony_ci event->attr.config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS) { 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci if (test_bit(ARMV8_PMUV3_PERFCTR_PC_WRITE_RETIRED, 99362306a36Sopenharmony_ci armpmu->pmceid_bitmap)) 99462306a36Sopenharmony_ci return ARMV8_PMUV3_PERFCTR_PC_WRITE_RETIRED; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci if (test_bit(ARMV8_PMUV3_PERFCTR_BR_RETIRED, 99762306a36Sopenharmony_ci armpmu->pmceid_bitmap)) 99862306a36Sopenharmony_ci return ARMV8_PMUV3_PERFCTR_BR_RETIRED; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci return HW_OP_UNSUPPORTED; 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci return armpmu_map_event(event, &armv8_pmuv3_perf_map, 100462306a36Sopenharmony_ci &armv8_pmuv3_perf_cache_map, 100562306a36Sopenharmony_ci ARMV8_PMU_EVTYPE_EVENT); 100662306a36Sopenharmony_ci} 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_cistatic int __armv8_pmuv3_map_event(struct perf_event *event, 100962306a36Sopenharmony_ci const unsigned (*extra_event_map) 101062306a36Sopenharmony_ci [PERF_COUNT_HW_MAX], 101162306a36Sopenharmony_ci const unsigned (*extra_cache_map) 101262306a36Sopenharmony_ci [PERF_COUNT_HW_CACHE_MAX] 101362306a36Sopenharmony_ci [PERF_COUNT_HW_CACHE_OP_MAX] 101462306a36Sopenharmony_ci [PERF_COUNT_HW_CACHE_RESULT_MAX]) 101562306a36Sopenharmony_ci{ 101662306a36Sopenharmony_ci int hw_event_id; 101762306a36Sopenharmony_ci struct arm_pmu *armpmu = to_arm_pmu(event->pmu); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci hw_event_id = __armv8_pmuv3_map_event_id(armpmu, event); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci /* 102262306a36Sopenharmony_ci * CHAIN events only work when paired with an adjacent counter, and it 102362306a36Sopenharmony_ci * never makes sense for a user to open one in isolation, as they'll be 102462306a36Sopenharmony_ci * rotated arbitrarily. 102562306a36Sopenharmony_ci */ 102662306a36Sopenharmony_ci if (hw_event_id == ARMV8_PMUV3_PERFCTR_CHAIN) 102762306a36Sopenharmony_ci return -EINVAL; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci if (armv8pmu_event_is_64bit(event)) 103062306a36Sopenharmony_ci event->hw.flags |= ARMPMU_EVT_64BIT; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci /* 103362306a36Sopenharmony_ci * User events must be allocated into a single counter, and so 103462306a36Sopenharmony_ci * must not be chained. 103562306a36Sopenharmony_ci * 103662306a36Sopenharmony_ci * Most 64-bit events require long counter support, but 64-bit 103762306a36Sopenharmony_ci * CPU_CYCLES events can be placed into the dedicated cycle 103862306a36Sopenharmony_ci * counter when this is free. 103962306a36Sopenharmony_ci */ 104062306a36Sopenharmony_ci if (armv8pmu_event_want_user_access(event)) { 104162306a36Sopenharmony_ci if (!(event->attach_state & PERF_ATTACH_TASK)) 104262306a36Sopenharmony_ci return -EINVAL; 104362306a36Sopenharmony_ci if (armv8pmu_event_is_64bit(event) && 104462306a36Sopenharmony_ci (hw_event_id != ARMV8_PMUV3_PERFCTR_CPU_CYCLES) && 104562306a36Sopenharmony_ci !armv8pmu_has_long_event(armpmu)) 104662306a36Sopenharmony_ci return -EOPNOTSUPP; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci event->hw.flags |= PERF_EVENT_FLAG_USER_READ_CNT; 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci /* Only expose micro/arch events supported by this PMU */ 105262306a36Sopenharmony_ci if ((hw_event_id > 0) && (hw_event_id < ARMV8_PMUV3_MAX_COMMON_EVENTS) 105362306a36Sopenharmony_ci && test_bit(hw_event_id, armpmu->pmceid_bitmap)) { 105462306a36Sopenharmony_ci return hw_event_id; 105562306a36Sopenharmony_ci } 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci return armpmu_map_event(event, extra_event_map, extra_cache_map, 105862306a36Sopenharmony_ci ARMV8_PMU_EVTYPE_EVENT); 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic int armv8_pmuv3_map_event(struct perf_event *event) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci return __armv8_pmuv3_map_event(event, NULL, NULL); 106462306a36Sopenharmony_ci} 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_cistatic int armv8_a53_map_event(struct perf_event *event) 106762306a36Sopenharmony_ci{ 106862306a36Sopenharmony_ci return __armv8_pmuv3_map_event(event, NULL, &armv8_a53_perf_cache_map); 106962306a36Sopenharmony_ci} 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_cistatic int armv8_a57_map_event(struct perf_event *event) 107262306a36Sopenharmony_ci{ 107362306a36Sopenharmony_ci return __armv8_pmuv3_map_event(event, NULL, &armv8_a57_perf_cache_map); 107462306a36Sopenharmony_ci} 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_cistatic int armv8_a73_map_event(struct perf_event *event) 107762306a36Sopenharmony_ci{ 107862306a36Sopenharmony_ci return __armv8_pmuv3_map_event(event, NULL, &armv8_a73_perf_cache_map); 107962306a36Sopenharmony_ci} 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_cistatic int armv8_thunder_map_event(struct perf_event *event) 108262306a36Sopenharmony_ci{ 108362306a36Sopenharmony_ci return __armv8_pmuv3_map_event(event, NULL, 108462306a36Sopenharmony_ci &armv8_thunder_perf_cache_map); 108562306a36Sopenharmony_ci} 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_cistatic int armv8_vulcan_map_event(struct perf_event *event) 108862306a36Sopenharmony_ci{ 108962306a36Sopenharmony_ci return __armv8_pmuv3_map_event(event, NULL, 109062306a36Sopenharmony_ci &armv8_vulcan_perf_cache_map); 109162306a36Sopenharmony_ci} 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_cistruct armv8pmu_probe_info { 109462306a36Sopenharmony_ci struct arm_pmu *pmu; 109562306a36Sopenharmony_ci bool present; 109662306a36Sopenharmony_ci}; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_cistatic void __armv8pmu_probe_pmu(void *info) 109962306a36Sopenharmony_ci{ 110062306a36Sopenharmony_ci struct armv8pmu_probe_info *probe = info; 110162306a36Sopenharmony_ci struct arm_pmu *cpu_pmu = probe->pmu; 110262306a36Sopenharmony_ci u64 pmceid_raw[2]; 110362306a36Sopenharmony_ci u32 pmceid[2]; 110462306a36Sopenharmony_ci int pmuver; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci pmuver = read_pmuver(); 110762306a36Sopenharmony_ci if (!pmuv3_implemented(pmuver)) 110862306a36Sopenharmony_ci return; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci cpu_pmu->pmuver = pmuver; 111162306a36Sopenharmony_ci probe->present = true; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci /* Read the nb of CNTx counters supported from PMNC */ 111462306a36Sopenharmony_ci cpu_pmu->num_events = (armv8pmu_pmcr_read() >> ARMV8_PMU_PMCR_N_SHIFT) 111562306a36Sopenharmony_ci & ARMV8_PMU_PMCR_N_MASK; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci /* Add the CPU cycles counter */ 111862306a36Sopenharmony_ci cpu_pmu->num_events += 1; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci pmceid[0] = pmceid_raw[0] = read_pmceid0(); 112162306a36Sopenharmony_ci pmceid[1] = pmceid_raw[1] = read_pmceid1(); 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci bitmap_from_arr32(cpu_pmu->pmceid_bitmap, 112462306a36Sopenharmony_ci pmceid, ARMV8_PMUV3_MAX_COMMON_EVENTS); 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci pmceid[0] = pmceid_raw[0] >> 32; 112762306a36Sopenharmony_ci pmceid[1] = pmceid_raw[1] >> 32; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci bitmap_from_arr32(cpu_pmu->pmceid_ext_bitmap, 113062306a36Sopenharmony_ci pmceid, ARMV8_PMUV3_MAX_COMMON_EVENTS); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci /* store PMMIR register for sysfs */ 113362306a36Sopenharmony_ci if (is_pmuv3p4(pmuver) && (pmceid_raw[1] & BIT(31))) 113462306a36Sopenharmony_ci cpu_pmu->reg_pmmir = read_pmmir(); 113562306a36Sopenharmony_ci else 113662306a36Sopenharmony_ci cpu_pmu->reg_pmmir = 0; 113762306a36Sopenharmony_ci} 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_cistatic int armv8pmu_probe_pmu(struct arm_pmu *cpu_pmu) 114062306a36Sopenharmony_ci{ 114162306a36Sopenharmony_ci struct armv8pmu_probe_info probe = { 114262306a36Sopenharmony_ci .pmu = cpu_pmu, 114362306a36Sopenharmony_ci .present = false, 114462306a36Sopenharmony_ci }; 114562306a36Sopenharmony_ci int ret; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci ret = smp_call_function_any(&cpu_pmu->supported_cpus, 114862306a36Sopenharmony_ci __armv8pmu_probe_pmu, 114962306a36Sopenharmony_ci &probe, 1); 115062306a36Sopenharmony_ci if (ret) 115162306a36Sopenharmony_ci return ret; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci return probe.present ? 0 : -ENODEV; 115462306a36Sopenharmony_ci} 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_cistatic void armv8pmu_disable_user_access_ipi(void *unused) 115762306a36Sopenharmony_ci{ 115862306a36Sopenharmony_ci armv8pmu_disable_user_access(); 115962306a36Sopenharmony_ci} 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_cistatic int armv8pmu_proc_user_access_handler(struct ctl_table *table, int write, 116262306a36Sopenharmony_ci void *buffer, size_t *lenp, loff_t *ppos) 116362306a36Sopenharmony_ci{ 116462306a36Sopenharmony_ci int ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); 116562306a36Sopenharmony_ci if (ret || !write || sysctl_perf_user_access) 116662306a36Sopenharmony_ci return ret; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci on_each_cpu(armv8pmu_disable_user_access_ipi, NULL, 1); 116962306a36Sopenharmony_ci return 0; 117062306a36Sopenharmony_ci} 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_cistatic struct ctl_table armv8_pmu_sysctl_table[] = { 117362306a36Sopenharmony_ci { 117462306a36Sopenharmony_ci .procname = "perf_user_access", 117562306a36Sopenharmony_ci .data = &sysctl_perf_user_access, 117662306a36Sopenharmony_ci .maxlen = sizeof(unsigned int), 117762306a36Sopenharmony_ci .mode = 0644, 117862306a36Sopenharmony_ci .proc_handler = armv8pmu_proc_user_access_handler, 117962306a36Sopenharmony_ci .extra1 = SYSCTL_ZERO, 118062306a36Sopenharmony_ci .extra2 = SYSCTL_ONE, 118162306a36Sopenharmony_ci }, 118262306a36Sopenharmony_ci { } 118362306a36Sopenharmony_ci}; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_cistatic void armv8_pmu_register_sysctl_table(void) 118662306a36Sopenharmony_ci{ 118762306a36Sopenharmony_ci static u32 tbl_registered = 0; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci if (!cmpxchg_relaxed(&tbl_registered, 0, 1)) 119062306a36Sopenharmony_ci register_sysctl("kernel", armv8_pmu_sysctl_table); 119162306a36Sopenharmony_ci} 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_cistatic int armv8_pmu_init(struct arm_pmu *cpu_pmu, char *name, 119462306a36Sopenharmony_ci int (*map_event)(struct perf_event *event), 119562306a36Sopenharmony_ci const struct attribute_group *events, 119662306a36Sopenharmony_ci const struct attribute_group *format, 119762306a36Sopenharmony_ci const struct attribute_group *caps) 119862306a36Sopenharmony_ci{ 119962306a36Sopenharmony_ci int ret = armv8pmu_probe_pmu(cpu_pmu); 120062306a36Sopenharmony_ci if (ret) 120162306a36Sopenharmony_ci return ret; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci cpu_pmu->handle_irq = armv8pmu_handle_irq; 120462306a36Sopenharmony_ci cpu_pmu->enable = armv8pmu_enable_event; 120562306a36Sopenharmony_ci cpu_pmu->disable = armv8pmu_disable_event; 120662306a36Sopenharmony_ci cpu_pmu->read_counter = armv8pmu_read_counter; 120762306a36Sopenharmony_ci cpu_pmu->write_counter = armv8pmu_write_counter; 120862306a36Sopenharmony_ci cpu_pmu->get_event_idx = armv8pmu_get_event_idx; 120962306a36Sopenharmony_ci cpu_pmu->clear_event_idx = armv8pmu_clear_event_idx; 121062306a36Sopenharmony_ci cpu_pmu->start = armv8pmu_start; 121162306a36Sopenharmony_ci cpu_pmu->stop = armv8pmu_stop; 121262306a36Sopenharmony_ci cpu_pmu->reset = armv8pmu_reset; 121362306a36Sopenharmony_ci cpu_pmu->set_event_filter = armv8pmu_set_event_filter; 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci cpu_pmu->pmu.event_idx = armv8pmu_user_event_idx; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci cpu_pmu->name = name; 121862306a36Sopenharmony_ci cpu_pmu->map_event = map_event; 121962306a36Sopenharmony_ci cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = events ? 122062306a36Sopenharmony_ci events : &armv8_pmuv3_events_attr_group; 122162306a36Sopenharmony_ci cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] = format ? 122262306a36Sopenharmony_ci format : &armv8_pmuv3_format_attr_group; 122362306a36Sopenharmony_ci cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_CAPS] = caps ? 122462306a36Sopenharmony_ci caps : &armv8_pmuv3_caps_attr_group; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci armv8_pmu_register_sysctl_table(); 122762306a36Sopenharmony_ci return 0; 122862306a36Sopenharmony_ci} 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_cistatic int armv8_pmu_init_nogroups(struct arm_pmu *cpu_pmu, char *name, 123162306a36Sopenharmony_ci int (*map_event)(struct perf_event *event)) 123262306a36Sopenharmony_ci{ 123362306a36Sopenharmony_ci return armv8_pmu_init(cpu_pmu, name, map_event, NULL, NULL, NULL); 123462306a36Sopenharmony_ci} 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci#define PMUV3_INIT_SIMPLE(name) \ 123762306a36Sopenharmony_cistatic int name##_pmu_init(struct arm_pmu *cpu_pmu) \ 123862306a36Sopenharmony_ci{ \ 123962306a36Sopenharmony_ci return armv8_pmu_init_nogroups(cpu_pmu, #name, armv8_pmuv3_map_event);\ 124062306a36Sopenharmony_ci} 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv8_pmuv3) 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv8_cortex_a34) 124562306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv8_cortex_a55) 124662306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv8_cortex_a65) 124762306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv8_cortex_a75) 124862306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv8_cortex_a76) 124962306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv8_cortex_a77) 125062306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv8_cortex_a78) 125162306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv9_cortex_a510) 125262306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv9_cortex_a520) 125362306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv9_cortex_a710) 125462306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv9_cortex_a715) 125562306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv9_cortex_a720) 125662306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv8_cortex_x1) 125762306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv9_cortex_x2) 125862306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv9_cortex_x3) 125962306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv9_cortex_x4) 126062306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv8_neoverse_e1) 126162306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv8_neoverse_n1) 126262306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv9_neoverse_n2) 126362306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv8_neoverse_v1) 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv8_nvidia_carmel) 126662306a36Sopenharmony_ciPMUV3_INIT_SIMPLE(armv8_nvidia_denver) 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_cistatic int armv8_a35_pmu_init(struct arm_pmu *cpu_pmu) 126962306a36Sopenharmony_ci{ 127062306a36Sopenharmony_ci return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a35", 127162306a36Sopenharmony_ci armv8_a53_map_event); 127262306a36Sopenharmony_ci} 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_cistatic int armv8_a53_pmu_init(struct arm_pmu *cpu_pmu) 127562306a36Sopenharmony_ci{ 127662306a36Sopenharmony_ci return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a53", 127762306a36Sopenharmony_ci armv8_a53_map_event); 127862306a36Sopenharmony_ci} 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_cistatic int armv8_a57_pmu_init(struct arm_pmu *cpu_pmu) 128162306a36Sopenharmony_ci{ 128262306a36Sopenharmony_ci return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a57", 128362306a36Sopenharmony_ci armv8_a57_map_event); 128462306a36Sopenharmony_ci} 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_cistatic int armv8_a72_pmu_init(struct arm_pmu *cpu_pmu) 128762306a36Sopenharmony_ci{ 128862306a36Sopenharmony_ci return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a72", 128962306a36Sopenharmony_ci armv8_a57_map_event); 129062306a36Sopenharmony_ci} 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_cistatic int armv8_a73_pmu_init(struct arm_pmu *cpu_pmu) 129362306a36Sopenharmony_ci{ 129462306a36Sopenharmony_ci return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a73", 129562306a36Sopenharmony_ci armv8_a73_map_event); 129662306a36Sopenharmony_ci} 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_cistatic int armv8_thunder_pmu_init(struct arm_pmu *cpu_pmu) 129962306a36Sopenharmony_ci{ 130062306a36Sopenharmony_ci return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cavium_thunder", 130162306a36Sopenharmony_ci armv8_thunder_map_event); 130262306a36Sopenharmony_ci} 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_cistatic int armv8_vulcan_pmu_init(struct arm_pmu *cpu_pmu) 130562306a36Sopenharmony_ci{ 130662306a36Sopenharmony_ci return armv8_pmu_init_nogroups(cpu_pmu, "armv8_brcm_vulcan", 130762306a36Sopenharmony_ci armv8_vulcan_map_event); 130862306a36Sopenharmony_ci} 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_cistatic const struct of_device_id armv8_pmu_of_device_ids[] = { 131162306a36Sopenharmony_ci {.compatible = "arm,armv8-pmuv3", .data = armv8_pmuv3_pmu_init}, 131262306a36Sopenharmony_ci {.compatible = "arm,cortex-a34-pmu", .data = armv8_cortex_a34_pmu_init}, 131362306a36Sopenharmony_ci {.compatible = "arm,cortex-a35-pmu", .data = armv8_a35_pmu_init}, 131462306a36Sopenharmony_ci {.compatible = "arm,cortex-a53-pmu", .data = armv8_a53_pmu_init}, 131562306a36Sopenharmony_ci {.compatible = "arm,cortex-a55-pmu", .data = armv8_cortex_a55_pmu_init}, 131662306a36Sopenharmony_ci {.compatible = "arm,cortex-a57-pmu", .data = armv8_a57_pmu_init}, 131762306a36Sopenharmony_ci {.compatible = "arm,cortex-a65-pmu", .data = armv8_cortex_a65_pmu_init}, 131862306a36Sopenharmony_ci {.compatible = "arm,cortex-a72-pmu", .data = armv8_a72_pmu_init}, 131962306a36Sopenharmony_ci {.compatible = "arm,cortex-a73-pmu", .data = armv8_a73_pmu_init}, 132062306a36Sopenharmony_ci {.compatible = "arm,cortex-a75-pmu", .data = armv8_cortex_a75_pmu_init}, 132162306a36Sopenharmony_ci {.compatible = "arm,cortex-a76-pmu", .data = armv8_cortex_a76_pmu_init}, 132262306a36Sopenharmony_ci {.compatible = "arm,cortex-a77-pmu", .data = armv8_cortex_a77_pmu_init}, 132362306a36Sopenharmony_ci {.compatible = "arm,cortex-a78-pmu", .data = armv8_cortex_a78_pmu_init}, 132462306a36Sopenharmony_ci {.compatible = "arm,cortex-a510-pmu", .data = armv9_cortex_a510_pmu_init}, 132562306a36Sopenharmony_ci {.compatible = "arm,cortex-a520-pmu", .data = armv9_cortex_a520_pmu_init}, 132662306a36Sopenharmony_ci {.compatible = "arm,cortex-a710-pmu", .data = armv9_cortex_a710_pmu_init}, 132762306a36Sopenharmony_ci {.compatible = "arm,cortex-a715-pmu", .data = armv9_cortex_a715_pmu_init}, 132862306a36Sopenharmony_ci {.compatible = "arm,cortex-a720-pmu", .data = armv9_cortex_a720_pmu_init}, 132962306a36Sopenharmony_ci {.compatible = "arm,cortex-x1-pmu", .data = armv8_cortex_x1_pmu_init}, 133062306a36Sopenharmony_ci {.compatible = "arm,cortex-x2-pmu", .data = armv9_cortex_x2_pmu_init}, 133162306a36Sopenharmony_ci {.compatible = "arm,cortex-x3-pmu", .data = armv9_cortex_x3_pmu_init}, 133262306a36Sopenharmony_ci {.compatible = "arm,cortex-x4-pmu", .data = armv9_cortex_x4_pmu_init}, 133362306a36Sopenharmony_ci {.compatible = "arm,neoverse-e1-pmu", .data = armv8_neoverse_e1_pmu_init}, 133462306a36Sopenharmony_ci {.compatible = "arm,neoverse-n1-pmu", .data = armv8_neoverse_n1_pmu_init}, 133562306a36Sopenharmony_ci {.compatible = "arm,neoverse-n2-pmu", .data = armv9_neoverse_n2_pmu_init}, 133662306a36Sopenharmony_ci {.compatible = "arm,neoverse-v1-pmu", .data = armv8_neoverse_v1_pmu_init}, 133762306a36Sopenharmony_ci {.compatible = "cavium,thunder-pmu", .data = armv8_thunder_pmu_init}, 133862306a36Sopenharmony_ci {.compatible = "brcm,vulcan-pmu", .data = armv8_vulcan_pmu_init}, 133962306a36Sopenharmony_ci {.compatible = "nvidia,carmel-pmu", .data = armv8_nvidia_carmel_pmu_init}, 134062306a36Sopenharmony_ci {.compatible = "nvidia,denver-pmu", .data = armv8_nvidia_denver_pmu_init}, 134162306a36Sopenharmony_ci {}, 134262306a36Sopenharmony_ci}; 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_cistatic int armv8_pmu_device_probe(struct platform_device *pdev) 134562306a36Sopenharmony_ci{ 134662306a36Sopenharmony_ci return arm_pmu_device_probe(pdev, armv8_pmu_of_device_ids, NULL); 134762306a36Sopenharmony_ci} 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_cistatic struct platform_driver armv8_pmu_driver = { 135062306a36Sopenharmony_ci .driver = { 135162306a36Sopenharmony_ci .name = ARMV8_PMU_PDEV_NAME, 135262306a36Sopenharmony_ci .of_match_table = armv8_pmu_of_device_ids, 135362306a36Sopenharmony_ci .suppress_bind_attrs = true, 135462306a36Sopenharmony_ci }, 135562306a36Sopenharmony_ci .probe = armv8_pmu_device_probe, 135662306a36Sopenharmony_ci}; 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_cistatic int __init armv8_pmu_driver_init(void) 135962306a36Sopenharmony_ci{ 136062306a36Sopenharmony_ci int ret; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci if (acpi_disabled) 136362306a36Sopenharmony_ci ret = platform_driver_register(&armv8_pmu_driver); 136462306a36Sopenharmony_ci else 136562306a36Sopenharmony_ci ret = arm_pmu_acpi_probe(armv8_pmuv3_pmu_init); 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci if (!ret) 136862306a36Sopenharmony_ci lockup_detector_retry_init(); 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci return ret; 137162306a36Sopenharmony_ci} 137262306a36Sopenharmony_cidevice_initcall(armv8_pmu_driver_init) 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_civoid arch_perf_update_userpage(struct perf_event *event, 137562306a36Sopenharmony_ci struct perf_event_mmap_page *userpg, u64 now) 137662306a36Sopenharmony_ci{ 137762306a36Sopenharmony_ci struct clock_read_data *rd; 137862306a36Sopenharmony_ci unsigned int seq; 137962306a36Sopenharmony_ci u64 ns; 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci userpg->cap_user_time = 0; 138262306a36Sopenharmony_ci userpg->cap_user_time_zero = 0; 138362306a36Sopenharmony_ci userpg->cap_user_time_short = 0; 138462306a36Sopenharmony_ci userpg->cap_user_rdpmc = armv8pmu_event_has_user_read(event); 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci if (userpg->cap_user_rdpmc) { 138762306a36Sopenharmony_ci if (event->hw.flags & ARMPMU_EVT_64BIT) 138862306a36Sopenharmony_ci userpg->pmc_width = 64; 138962306a36Sopenharmony_ci else 139062306a36Sopenharmony_ci userpg->pmc_width = 32; 139162306a36Sopenharmony_ci } 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci do { 139462306a36Sopenharmony_ci rd = sched_clock_read_begin(&seq); 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci if (rd->read_sched_clock != arch_timer_read_counter) 139762306a36Sopenharmony_ci return; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci userpg->time_mult = rd->mult; 140062306a36Sopenharmony_ci userpg->time_shift = rd->shift; 140162306a36Sopenharmony_ci userpg->time_zero = rd->epoch_ns; 140262306a36Sopenharmony_ci userpg->time_cycles = rd->epoch_cyc; 140362306a36Sopenharmony_ci userpg->time_mask = rd->sched_clock_mask; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci /* 140662306a36Sopenharmony_ci * Subtract the cycle base, such that software that 140762306a36Sopenharmony_ci * doesn't know about cap_user_time_short still 'works' 140862306a36Sopenharmony_ci * assuming no wraps. 140962306a36Sopenharmony_ci */ 141062306a36Sopenharmony_ci ns = mul_u64_u32_shr(rd->epoch_cyc, rd->mult, rd->shift); 141162306a36Sopenharmony_ci userpg->time_zero -= ns; 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci } while (sched_clock_read_retry(seq)); 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci userpg->time_offset = userpg->time_zero - now; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci /* 141862306a36Sopenharmony_ci * time_shift is not expected to be greater than 31 due to 141962306a36Sopenharmony_ci * the original published conversion algorithm shifting a 142062306a36Sopenharmony_ci * 32-bit value (now specifies a 64-bit value) - refer 142162306a36Sopenharmony_ci * perf_event_mmap_page documentation in perf_event.h. 142262306a36Sopenharmony_ci */ 142362306a36Sopenharmony_ci if (userpg->time_shift == 32) { 142462306a36Sopenharmony_ci userpg->time_shift = 31; 142562306a36Sopenharmony_ci userpg->time_mult >>= 1; 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci /* 142962306a36Sopenharmony_ci * Internal timekeeping for enabled/running/stopped times 143062306a36Sopenharmony_ci * is always computed with the sched_clock. 143162306a36Sopenharmony_ci */ 143262306a36Sopenharmony_ci userpg->cap_user_time = 1; 143362306a36Sopenharmony_ci userpg->cap_user_time_zero = 1; 143462306a36Sopenharmony_ci userpg->cap_user_time_short = 1; 143562306a36Sopenharmony_ci} 1436