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