162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci#undef DEBUG
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci/*
562306a36Sopenharmony_ci * ARM performance counter support.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 2009 picoChip Designs, Ltd., Jamie Iles
862306a36Sopenharmony_ci * Copyright (C) 2010 ARM Ltd., Will Deacon <will.deacon@arm.com>
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * This code is based on the sparc64 perf event code, which is in turn based
1162306a36Sopenharmony_ci * on the x86 code.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci#define pr_fmt(fmt) "hw perfevents: " fmt
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/bitmap.h>
1662306a36Sopenharmony_ci#include <linux/cpumask.h>
1762306a36Sopenharmony_ci#include <linux/cpu_pm.h>
1862306a36Sopenharmony_ci#include <linux/export.h>
1962306a36Sopenharmony_ci#include <linux/kernel.h>
2062306a36Sopenharmony_ci#include <linux/perf/arm_pmu.h>
2162306a36Sopenharmony_ci#include <linux/slab.h>
2262306a36Sopenharmony_ci#include <linux/sched/clock.h>
2362306a36Sopenharmony_ci#include <linux/spinlock.h>
2462306a36Sopenharmony_ci#include <linux/irq.h>
2562306a36Sopenharmony_ci#include <linux/irqdesc.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include <asm/irq_regs.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic int armpmu_count_irq_users(const int irq);
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistruct pmu_irq_ops {
3262306a36Sopenharmony_ci	void (*enable_pmuirq)(unsigned int irq);
3362306a36Sopenharmony_ci	void (*disable_pmuirq)(unsigned int irq);
3462306a36Sopenharmony_ci	void (*free_pmuirq)(unsigned int irq, int cpu, void __percpu *devid);
3562306a36Sopenharmony_ci};
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic void armpmu_free_pmuirq(unsigned int irq, int cpu, void __percpu *devid)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	free_irq(irq, per_cpu_ptr(devid, cpu));
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic const struct pmu_irq_ops pmuirq_ops = {
4362306a36Sopenharmony_ci	.enable_pmuirq = enable_irq,
4462306a36Sopenharmony_ci	.disable_pmuirq = disable_irq_nosync,
4562306a36Sopenharmony_ci	.free_pmuirq = armpmu_free_pmuirq
4662306a36Sopenharmony_ci};
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic void armpmu_free_pmunmi(unsigned int irq, int cpu, void __percpu *devid)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	free_nmi(irq, per_cpu_ptr(devid, cpu));
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic const struct pmu_irq_ops pmunmi_ops = {
5462306a36Sopenharmony_ci	.enable_pmuirq = enable_nmi,
5562306a36Sopenharmony_ci	.disable_pmuirq = disable_nmi_nosync,
5662306a36Sopenharmony_ci	.free_pmuirq = armpmu_free_pmunmi
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic void armpmu_enable_percpu_pmuirq(unsigned int irq)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	enable_percpu_irq(irq, IRQ_TYPE_NONE);
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic void armpmu_free_percpu_pmuirq(unsigned int irq, int cpu,
6562306a36Sopenharmony_ci				   void __percpu *devid)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	if (armpmu_count_irq_users(irq) == 1)
6862306a36Sopenharmony_ci		free_percpu_irq(irq, devid);
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic const struct pmu_irq_ops percpu_pmuirq_ops = {
7262306a36Sopenharmony_ci	.enable_pmuirq = armpmu_enable_percpu_pmuirq,
7362306a36Sopenharmony_ci	.disable_pmuirq = disable_percpu_irq,
7462306a36Sopenharmony_ci	.free_pmuirq = armpmu_free_percpu_pmuirq
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic void armpmu_enable_percpu_pmunmi(unsigned int irq)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	if (!prepare_percpu_nmi(irq))
8062306a36Sopenharmony_ci		enable_percpu_nmi(irq, IRQ_TYPE_NONE);
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic void armpmu_disable_percpu_pmunmi(unsigned int irq)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	disable_percpu_nmi(irq);
8662306a36Sopenharmony_ci	teardown_percpu_nmi(irq);
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic void armpmu_free_percpu_pmunmi(unsigned int irq, int cpu,
9062306a36Sopenharmony_ci				      void __percpu *devid)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	if (armpmu_count_irq_users(irq) == 1)
9362306a36Sopenharmony_ci		free_percpu_nmi(irq, devid);
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic const struct pmu_irq_ops percpu_pmunmi_ops = {
9762306a36Sopenharmony_ci	.enable_pmuirq = armpmu_enable_percpu_pmunmi,
9862306a36Sopenharmony_ci	.disable_pmuirq = armpmu_disable_percpu_pmunmi,
9962306a36Sopenharmony_ci	.free_pmuirq = armpmu_free_percpu_pmunmi
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct arm_pmu *, cpu_armpmu);
10362306a36Sopenharmony_cistatic DEFINE_PER_CPU(int, cpu_irq);
10462306a36Sopenharmony_cistatic DEFINE_PER_CPU(const struct pmu_irq_ops *, cpu_irq_ops);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic bool has_nmi;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic inline u64 arm_pmu_event_max_period(struct perf_event *event)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	if (event->hw.flags & ARMPMU_EVT_64BIT)
11162306a36Sopenharmony_ci		return GENMASK_ULL(63, 0);
11262306a36Sopenharmony_ci	else if (event->hw.flags & ARMPMU_EVT_63BIT)
11362306a36Sopenharmony_ci		return GENMASK_ULL(62, 0);
11462306a36Sopenharmony_ci	else if (event->hw.flags & ARMPMU_EVT_47BIT)
11562306a36Sopenharmony_ci		return GENMASK_ULL(46, 0);
11662306a36Sopenharmony_ci	else
11762306a36Sopenharmony_ci		return GENMASK_ULL(31, 0);
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic int
12162306a36Sopenharmony_ciarmpmu_map_cache_event(const unsigned (*cache_map)
12262306a36Sopenharmony_ci				      [PERF_COUNT_HW_CACHE_MAX]
12362306a36Sopenharmony_ci				      [PERF_COUNT_HW_CACHE_OP_MAX]
12462306a36Sopenharmony_ci				      [PERF_COUNT_HW_CACHE_RESULT_MAX],
12562306a36Sopenharmony_ci		       u64 config)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	unsigned int cache_type, cache_op, cache_result, ret;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	cache_type = (config >>  0) & 0xff;
13062306a36Sopenharmony_ci	if (cache_type >= PERF_COUNT_HW_CACHE_MAX)
13162306a36Sopenharmony_ci		return -EINVAL;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	cache_op = (config >>  8) & 0xff;
13462306a36Sopenharmony_ci	if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX)
13562306a36Sopenharmony_ci		return -EINVAL;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	cache_result = (config >> 16) & 0xff;
13862306a36Sopenharmony_ci	if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
13962306a36Sopenharmony_ci		return -EINVAL;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	if (!cache_map)
14262306a36Sopenharmony_ci		return -ENOENT;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	ret = (int)(*cache_map)[cache_type][cache_op][cache_result];
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (ret == CACHE_OP_UNSUPPORTED)
14762306a36Sopenharmony_ci		return -ENOENT;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	return ret;
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic int
15362306a36Sopenharmony_ciarmpmu_map_hw_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	int mapping;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	if (config >= PERF_COUNT_HW_MAX)
15862306a36Sopenharmony_ci		return -EINVAL;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	if (!event_map)
16162306a36Sopenharmony_ci		return -ENOENT;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	mapping = (*event_map)[config];
16462306a36Sopenharmony_ci	return mapping == HW_OP_UNSUPPORTED ? -ENOENT : mapping;
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic int
16862306a36Sopenharmony_ciarmpmu_map_raw_event(u32 raw_event_mask, u64 config)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	return (int)(config & raw_event_mask);
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ciint
17462306a36Sopenharmony_ciarmpmu_map_event(struct perf_event *event,
17562306a36Sopenharmony_ci		 const unsigned (*event_map)[PERF_COUNT_HW_MAX],
17662306a36Sopenharmony_ci		 const unsigned (*cache_map)
17762306a36Sopenharmony_ci				[PERF_COUNT_HW_CACHE_MAX]
17862306a36Sopenharmony_ci				[PERF_COUNT_HW_CACHE_OP_MAX]
17962306a36Sopenharmony_ci				[PERF_COUNT_HW_CACHE_RESULT_MAX],
18062306a36Sopenharmony_ci		 u32 raw_event_mask)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	u64 config = event->attr.config;
18362306a36Sopenharmony_ci	int type = event->attr.type;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (type == event->pmu->type)
18662306a36Sopenharmony_ci		return armpmu_map_raw_event(raw_event_mask, config);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	switch (type) {
18962306a36Sopenharmony_ci	case PERF_TYPE_HARDWARE:
19062306a36Sopenharmony_ci		return armpmu_map_hw_event(event_map, config);
19162306a36Sopenharmony_ci	case PERF_TYPE_HW_CACHE:
19262306a36Sopenharmony_ci		return armpmu_map_cache_event(cache_map, config);
19362306a36Sopenharmony_ci	case PERF_TYPE_RAW:
19462306a36Sopenharmony_ci		return armpmu_map_raw_event(raw_event_mask, config);
19562306a36Sopenharmony_ci	}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	return -ENOENT;
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ciint armpmu_event_set_period(struct perf_event *event)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
20362306a36Sopenharmony_ci	struct hw_perf_event *hwc = &event->hw;
20462306a36Sopenharmony_ci	s64 left = local64_read(&hwc->period_left);
20562306a36Sopenharmony_ci	s64 period = hwc->sample_period;
20662306a36Sopenharmony_ci	u64 max_period;
20762306a36Sopenharmony_ci	int ret = 0;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	max_period = arm_pmu_event_max_period(event);
21062306a36Sopenharmony_ci	if (unlikely(left <= -period)) {
21162306a36Sopenharmony_ci		left = period;
21262306a36Sopenharmony_ci		local64_set(&hwc->period_left, left);
21362306a36Sopenharmony_ci		hwc->last_period = period;
21462306a36Sopenharmony_ci		ret = 1;
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	if (unlikely(left <= 0)) {
21862306a36Sopenharmony_ci		left += period;
21962306a36Sopenharmony_ci		local64_set(&hwc->period_left, left);
22062306a36Sopenharmony_ci		hwc->last_period = period;
22162306a36Sopenharmony_ci		ret = 1;
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	/*
22562306a36Sopenharmony_ci	 * Limit the maximum period to prevent the counter value
22662306a36Sopenharmony_ci	 * from overtaking the one we are about to program. In
22762306a36Sopenharmony_ci	 * effect we are reducing max_period to account for
22862306a36Sopenharmony_ci	 * interrupt latency (and we are being very conservative).
22962306a36Sopenharmony_ci	 */
23062306a36Sopenharmony_ci	if (left > (max_period >> 1))
23162306a36Sopenharmony_ci		left = (max_period >> 1);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	local64_set(&hwc->prev_count, (u64)-left);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	armpmu->write_counter(event, (u64)(-left) & max_period);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	perf_event_update_userpage(event);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	return ret;
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ciu64 armpmu_event_update(struct perf_event *event)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
24562306a36Sopenharmony_ci	struct hw_perf_event *hwc = &event->hw;
24662306a36Sopenharmony_ci	u64 delta, prev_raw_count, new_raw_count;
24762306a36Sopenharmony_ci	u64 max_period = arm_pmu_event_max_period(event);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ciagain:
25062306a36Sopenharmony_ci	prev_raw_count = local64_read(&hwc->prev_count);
25162306a36Sopenharmony_ci	new_raw_count = armpmu->read_counter(event);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
25462306a36Sopenharmony_ci			     new_raw_count) != prev_raw_count)
25562306a36Sopenharmony_ci		goto again;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	delta = (new_raw_count - prev_raw_count) & max_period;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	local64_add(delta, &event->count);
26062306a36Sopenharmony_ci	local64_sub(delta, &hwc->period_left);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	return new_raw_count;
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic void
26662306a36Sopenharmony_ciarmpmu_read(struct perf_event *event)
26762306a36Sopenharmony_ci{
26862306a36Sopenharmony_ci	armpmu_event_update(event);
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic void
27262306a36Sopenharmony_ciarmpmu_stop(struct perf_event *event, int flags)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
27562306a36Sopenharmony_ci	struct hw_perf_event *hwc = &event->hw;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	/*
27862306a36Sopenharmony_ci	 * ARM pmu always has to update the counter, so ignore
27962306a36Sopenharmony_ci	 * PERF_EF_UPDATE, see comments in armpmu_start().
28062306a36Sopenharmony_ci	 */
28162306a36Sopenharmony_ci	if (!(hwc->state & PERF_HES_STOPPED)) {
28262306a36Sopenharmony_ci		armpmu->disable(event);
28362306a36Sopenharmony_ci		armpmu_event_update(event);
28462306a36Sopenharmony_ci		hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
28562306a36Sopenharmony_ci	}
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic void armpmu_start(struct perf_event *event, int flags)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
29162306a36Sopenharmony_ci	struct hw_perf_event *hwc = &event->hw;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	/*
29462306a36Sopenharmony_ci	 * ARM pmu always has to reprogram the period, so ignore
29562306a36Sopenharmony_ci	 * PERF_EF_RELOAD, see the comment below.
29662306a36Sopenharmony_ci	 */
29762306a36Sopenharmony_ci	if (flags & PERF_EF_RELOAD)
29862306a36Sopenharmony_ci		WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	hwc->state = 0;
30162306a36Sopenharmony_ci	/*
30262306a36Sopenharmony_ci	 * Set the period again. Some counters can't be stopped, so when we
30362306a36Sopenharmony_ci	 * were stopped we simply disabled the IRQ source and the counter
30462306a36Sopenharmony_ci	 * may have been left counting. If we don't do this step then we may
30562306a36Sopenharmony_ci	 * get an interrupt too soon or *way* too late if the overflow has
30662306a36Sopenharmony_ci	 * happened since disabling.
30762306a36Sopenharmony_ci	 */
30862306a36Sopenharmony_ci	armpmu_event_set_period(event);
30962306a36Sopenharmony_ci	armpmu->enable(event);
31062306a36Sopenharmony_ci}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_cistatic void
31362306a36Sopenharmony_ciarmpmu_del(struct perf_event *event, int flags)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
31662306a36Sopenharmony_ci	struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events);
31762306a36Sopenharmony_ci	struct hw_perf_event *hwc = &event->hw;
31862306a36Sopenharmony_ci	int idx = hwc->idx;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	armpmu_stop(event, PERF_EF_UPDATE);
32162306a36Sopenharmony_ci	hw_events->events[idx] = NULL;
32262306a36Sopenharmony_ci	armpmu->clear_event_idx(hw_events, event);
32362306a36Sopenharmony_ci	perf_event_update_userpage(event);
32462306a36Sopenharmony_ci	/* Clear the allocated counter */
32562306a36Sopenharmony_ci	hwc->idx = -1;
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic int
32962306a36Sopenharmony_ciarmpmu_add(struct perf_event *event, int flags)
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
33262306a36Sopenharmony_ci	struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events);
33362306a36Sopenharmony_ci	struct hw_perf_event *hwc = &event->hw;
33462306a36Sopenharmony_ci	int idx;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	/* An event following a process won't be stopped earlier */
33762306a36Sopenharmony_ci	if (!cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus))
33862306a36Sopenharmony_ci		return -ENOENT;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	/* If we don't have a space for the counter then finish early. */
34162306a36Sopenharmony_ci	idx = armpmu->get_event_idx(hw_events, event);
34262306a36Sopenharmony_ci	if (idx < 0)
34362306a36Sopenharmony_ci		return idx;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/*
34662306a36Sopenharmony_ci	 * If there is an event in the counter we are going to use then make
34762306a36Sopenharmony_ci	 * sure it is disabled.
34862306a36Sopenharmony_ci	 */
34962306a36Sopenharmony_ci	event->hw.idx = idx;
35062306a36Sopenharmony_ci	armpmu->disable(event);
35162306a36Sopenharmony_ci	hw_events->events[idx] = event;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
35462306a36Sopenharmony_ci	if (flags & PERF_EF_START)
35562306a36Sopenharmony_ci		armpmu_start(event, PERF_EF_RELOAD);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	/* Propagate our changes to the userspace mapping. */
35862306a36Sopenharmony_ci	perf_event_update_userpage(event);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	return 0;
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic int
36462306a36Sopenharmony_civalidate_event(struct pmu *pmu, struct pmu_hw_events *hw_events,
36562306a36Sopenharmony_ci			       struct perf_event *event)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	struct arm_pmu *armpmu;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	if (is_software_event(event))
37062306a36Sopenharmony_ci		return 1;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	/*
37362306a36Sopenharmony_ci	 * Reject groups spanning multiple HW PMUs (e.g. CPU + CCI). The
37462306a36Sopenharmony_ci	 * core perf code won't check that the pmu->ctx == leader->ctx
37562306a36Sopenharmony_ci	 * until after pmu->event_init(event).
37662306a36Sopenharmony_ci	 */
37762306a36Sopenharmony_ci	if (event->pmu != pmu)
37862306a36Sopenharmony_ci		return 0;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	if (event->state < PERF_EVENT_STATE_OFF)
38162306a36Sopenharmony_ci		return 1;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	if (event->state == PERF_EVENT_STATE_OFF && !event->attr.enable_on_exec)
38462306a36Sopenharmony_ci		return 1;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	armpmu = to_arm_pmu(event->pmu);
38762306a36Sopenharmony_ci	return armpmu->get_event_idx(hw_events, event) >= 0;
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic int
39162306a36Sopenharmony_civalidate_group(struct perf_event *event)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	struct perf_event *sibling, *leader = event->group_leader;
39462306a36Sopenharmony_ci	struct pmu_hw_events fake_pmu;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/*
39762306a36Sopenharmony_ci	 * Initialise the fake PMU. We only need to populate the
39862306a36Sopenharmony_ci	 * used_mask for the purposes of validation.
39962306a36Sopenharmony_ci	 */
40062306a36Sopenharmony_ci	memset(&fake_pmu.used_mask, 0, sizeof(fake_pmu.used_mask));
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	if (!validate_event(event->pmu, &fake_pmu, leader))
40362306a36Sopenharmony_ci		return -EINVAL;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	if (event == leader)
40662306a36Sopenharmony_ci		return 0;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	for_each_sibling_event(sibling, leader) {
40962306a36Sopenharmony_ci		if (!validate_event(event->pmu, &fake_pmu, sibling))
41062306a36Sopenharmony_ci			return -EINVAL;
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (!validate_event(event->pmu, &fake_pmu, event))
41462306a36Sopenharmony_ci		return -EINVAL;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	return 0;
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cistatic irqreturn_t armpmu_dispatch_irq(int irq, void *dev)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	struct arm_pmu *armpmu;
42262306a36Sopenharmony_ci	int ret;
42362306a36Sopenharmony_ci	u64 start_clock, finish_clock;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	/*
42662306a36Sopenharmony_ci	 * we request the IRQ with a (possibly percpu) struct arm_pmu**, but
42762306a36Sopenharmony_ci	 * the handlers expect a struct arm_pmu*. The percpu_irq framework will
42862306a36Sopenharmony_ci	 * do any necessary shifting, we just need to perform the first
42962306a36Sopenharmony_ci	 * dereference.
43062306a36Sopenharmony_ci	 */
43162306a36Sopenharmony_ci	armpmu = *(void **)dev;
43262306a36Sopenharmony_ci	if (WARN_ON_ONCE(!armpmu))
43362306a36Sopenharmony_ci		return IRQ_NONE;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	start_clock = sched_clock();
43662306a36Sopenharmony_ci	ret = armpmu->handle_irq(armpmu);
43762306a36Sopenharmony_ci	finish_clock = sched_clock();
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	perf_sample_event_took(finish_clock - start_clock);
44062306a36Sopenharmony_ci	return ret;
44162306a36Sopenharmony_ci}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cistatic int
44462306a36Sopenharmony_ci__hw_perf_event_init(struct perf_event *event)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
44762306a36Sopenharmony_ci	struct hw_perf_event *hwc = &event->hw;
44862306a36Sopenharmony_ci	int mapping;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	hwc->flags = 0;
45162306a36Sopenharmony_ci	mapping = armpmu->map_event(event);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	if (mapping < 0) {
45462306a36Sopenharmony_ci		pr_debug("event %x:%llx not supported\n", event->attr.type,
45562306a36Sopenharmony_ci			 event->attr.config);
45662306a36Sopenharmony_ci		return mapping;
45762306a36Sopenharmony_ci	}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	/*
46062306a36Sopenharmony_ci	 * We don't assign an index until we actually place the event onto
46162306a36Sopenharmony_ci	 * hardware. Use -1 to signify that we haven't decided where to put it
46262306a36Sopenharmony_ci	 * yet. For SMP systems, each core has it's own PMU so we can't do any
46362306a36Sopenharmony_ci	 * clever allocation or constraints checking at this point.
46462306a36Sopenharmony_ci	 */
46562306a36Sopenharmony_ci	hwc->idx		= -1;
46662306a36Sopenharmony_ci	hwc->config_base	= 0;
46762306a36Sopenharmony_ci	hwc->config		= 0;
46862306a36Sopenharmony_ci	hwc->event_base		= 0;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	/*
47162306a36Sopenharmony_ci	 * Check whether we need to exclude the counter from certain modes.
47262306a36Sopenharmony_ci	 */
47362306a36Sopenharmony_ci	if (armpmu->set_event_filter &&
47462306a36Sopenharmony_ci	    armpmu->set_event_filter(hwc, &event->attr)) {
47562306a36Sopenharmony_ci		pr_debug("ARM performance counters do not support "
47662306a36Sopenharmony_ci			 "mode exclusion\n");
47762306a36Sopenharmony_ci		return -EOPNOTSUPP;
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	/*
48162306a36Sopenharmony_ci	 * Store the event encoding into the config_base field.
48262306a36Sopenharmony_ci	 */
48362306a36Sopenharmony_ci	hwc->config_base	    |= (unsigned long)mapping;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	if (!is_sampling_event(event)) {
48662306a36Sopenharmony_ci		/*
48762306a36Sopenharmony_ci		 * For non-sampling runs, limit the sample_period to half
48862306a36Sopenharmony_ci		 * of the counter width. That way, the new counter value
48962306a36Sopenharmony_ci		 * is far less likely to overtake the previous one unless
49062306a36Sopenharmony_ci		 * you have some serious IRQ latency issues.
49162306a36Sopenharmony_ci		 */
49262306a36Sopenharmony_ci		hwc->sample_period  = arm_pmu_event_max_period(event) >> 1;
49362306a36Sopenharmony_ci		hwc->last_period    = hwc->sample_period;
49462306a36Sopenharmony_ci		local64_set(&hwc->period_left, hwc->sample_period);
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	return validate_group(event);
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cistatic int armpmu_event_init(struct perf_event *event)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	/*
50562306a36Sopenharmony_ci	 * Reject CPU-affine events for CPUs that are of a different class to
50662306a36Sopenharmony_ci	 * that which this PMU handles. Process-following events (where
50762306a36Sopenharmony_ci	 * event->cpu == -1) can be migrated between CPUs, and thus we have to
50862306a36Sopenharmony_ci	 * reject them later (in armpmu_add) if they're scheduled on a
50962306a36Sopenharmony_ci	 * different class of CPU.
51062306a36Sopenharmony_ci	 */
51162306a36Sopenharmony_ci	if (event->cpu != -1 &&
51262306a36Sopenharmony_ci		!cpumask_test_cpu(event->cpu, &armpmu->supported_cpus))
51362306a36Sopenharmony_ci		return -ENOENT;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	/* does not support taken branch sampling */
51662306a36Sopenharmony_ci	if (has_branch_stack(event))
51762306a36Sopenharmony_ci		return -EOPNOTSUPP;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	return __hw_perf_event_init(event);
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic void armpmu_enable(struct pmu *pmu)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	struct arm_pmu *armpmu = to_arm_pmu(pmu);
52562306a36Sopenharmony_ci	struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events);
52662306a36Sopenharmony_ci	bool enabled = !bitmap_empty(hw_events->used_mask, armpmu->num_events);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	/* For task-bound events we may be called on other CPUs */
52962306a36Sopenharmony_ci	if (!cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus))
53062306a36Sopenharmony_ci		return;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	if (enabled)
53362306a36Sopenharmony_ci		armpmu->start(armpmu);
53462306a36Sopenharmony_ci}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_cistatic void armpmu_disable(struct pmu *pmu)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	struct arm_pmu *armpmu = to_arm_pmu(pmu);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	/* For task-bound events we may be called on other CPUs */
54162306a36Sopenharmony_ci	if (!cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus))
54262306a36Sopenharmony_ci		return;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	armpmu->stop(armpmu);
54562306a36Sopenharmony_ci}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci/*
54862306a36Sopenharmony_ci * In heterogeneous systems, events are specific to a particular
54962306a36Sopenharmony_ci * microarchitecture, and aren't suitable for another. Thus, only match CPUs of
55062306a36Sopenharmony_ci * the same microarchitecture.
55162306a36Sopenharmony_ci */
55262306a36Sopenharmony_cistatic bool armpmu_filter(struct pmu *pmu, int cpu)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	struct arm_pmu *armpmu = to_arm_pmu(pmu);
55562306a36Sopenharmony_ci	return !cpumask_test_cpu(cpu, &armpmu->supported_cpus);
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_cistatic ssize_t cpus_show(struct device *dev,
55962306a36Sopenharmony_ci			 struct device_attribute *attr, char *buf)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	struct arm_pmu *armpmu = to_arm_pmu(dev_get_drvdata(dev));
56262306a36Sopenharmony_ci	return cpumap_print_to_pagebuf(true, buf, &armpmu->supported_cpus);
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(cpus);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_cistatic struct attribute *armpmu_common_attrs[] = {
56862306a36Sopenharmony_ci	&dev_attr_cpus.attr,
56962306a36Sopenharmony_ci	NULL,
57062306a36Sopenharmony_ci};
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_cistatic const struct attribute_group armpmu_common_attr_group = {
57362306a36Sopenharmony_ci	.attrs = armpmu_common_attrs,
57462306a36Sopenharmony_ci};
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_cistatic int armpmu_count_irq_users(const int irq)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	int cpu, count = 0;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	for_each_possible_cpu(cpu) {
58162306a36Sopenharmony_ci		if (per_cpu(cpu_irq, cpu) == irq)
58262306a36Sopenharmony_ci			count++;
58362306a36Sopenharmony_ci	}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	return count;
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_cistatic const struct pmu_irq_ops *armpmu_find_irq_ops(int irq)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	const struct pmu_irq_ops *ops = NULL;
59162306a36Sopenharmony_ci	int cpu;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	for_each_possible_cpu(cpu) {
59462306a36Sopenharmony_ci		if (per_cpu(cpu_irq, cpu) != irq)
59562306a36Sopenharmony_ci			continue;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci		ops = per_cpu(cpu_irq_ops, cpu);
59862306a36Sopenharmony_ci		if (ops)
59962306a36Sopenharmony_ci			break;
60062306a36Sopenharmony_ci	}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	return ops;
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_civoid armpmu_free_irq(int irq, int cpu)
60662306a36Sopenharmony_ci{
60762306a36Sopenharmony_ci	if (per_cpu(cpu_irq, cpu) == 0)
60862306a36Sopenharmony_ci		return;
60962306a36Sopenharmony_ci	if (WARN_ON(irq != per_cpu(cpu_irq, cpu)))
61062306a36Sopenharmony_ci		return;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	per_cpu(cpu_irq_ops, cpu)->free_pmuirq(irq, cpu, &cpu_armpmu);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	per_cpu(cpu_irq, cpu) = 0;
61562306a36Sopenharmony_ci	per_cpu(cpu_irq_ops, cpu) = NULL;
61662306a36Sopenharmony_ci}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ciint armpmu_request_irq(int irq, int cpu)
61962306a36Sopenharmony_ci{
62062306a36Sopenharmony_ci	int err = 0;
62162306a36Sopenharmony_ci	const irq_handler_t handler = armpmu_dispatch_irq;
62262306a36Sopenharmony_ci	const struct pmu_irq_ops *irq_ops;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	if (!irq)
62562306a36Sopenharmony_ci		return 0;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	if (!irq_is_percpu_devid(irq)) {
62862306a36Sopenharmony_ci		unsigned long irq_flags;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci		err = irq_force_affinity(irq, cpumask_of(cpu));
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci		if (err && num_possible_cpus() > 1) {
63362306a36Sopenharmony_ci			pr_warn("unable to set irq affinity (irq=%d, cpu=%u)\n",
63462306a36Sopenharmony_ci				irq, cpu);
63562306a36Sopenharmony_ci			goto err_out;
63662306a36Sopenharmony_ci		}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci		irq_flags = IRQF_PERCPU |
63962306a36Sopenharmony_ci			    IRQF_NOBALANCING | IRQF_NO_AUTOEN |
64062306a36Sopenharmony_ci			    IRQF_NO_THREAD;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci		err = request_nmi(irq, handler, irq_flags, "arm-pmu",
64362306a36Sopenharmony_ci				  per_cpu_ptr(&cpu_armpmu, cpu));
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci		/* If cannot get an NMI, get a normal interrupt */
64662306a36Sopenharmony_ci		if (err) {
64762306a36Sopenharmony_ci			err = request_irq(irq, handler, irq_flags, "arm-pmu",
64862306a36Sopenharmony_ci					  per_cpu_ptr(&cpu_armpmu, cpu));
64962306a36Sopenharmony_ci			irq_ops = &pmuirq_ops;
65062306a36Sopenharmony_ci		} else {
65162306a36Sopenharmony_ci			has_nmi = true;
65262306a36Sopenharmony_ci			irq_ops = &pmunmi_ops;
65362306a36Sopenharmony_ci		}
65462306a36Sopenharmony_ci	} else if (armpmu_count_irq_users(irq) == 0) {
65562306a36Sopenharmony_ci		err = request_percpu_nmi(irq, handler, "arm-pmu", &cpu_armpmu);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci		/* If cannot get an NMI, get a normal interrupt */
65862306a36Sopenharmony_ci		if (err) {
65962306a36Sopenharmony_ci			err = request_percpu_irq(irq, handler, "arm-pmu",
66062306a36Sopenharmony_ci						 &cpu_armpmu);
66162306a36Sopenharmony_ci			irq_ops = &percpu_pmuirq_ops;
66262306a36Sopenharmony_ci		} else {
66362306a36Sopenharmony_ci			has_nmi = true;
66462306a36Sopenharmony_ci			irq_ops = &percpu_pmunmi_ops;
66562306a36Sopenharmony_ci		}
66662306a36Sopenharmony_ci	} else {
66762306a36Sopenharmony_ci		/* Per cpudevid irq was already requested by another CPU */
66862306a36Sopenharmony_ci		irq_ops = armpmu_find_irq_ops(irq);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci		if (WARN_ON(!irq_ops))
67162306a36Sopenharmony_ci			err = -EINVAL;
67262306a36Sopenharmony_ci	}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	if (err)
67562306a36Sopenharmony_ci		goto err_out;
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	per_cpu(cpu_irq, cpu) = irq;
67862306a36Sopenharmony_ci	per_cpu(cpu_irq_ops, cpu) = irq_ops;
67962306a36Sopenharmony_ci	return 0;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_cierr_out:
68262306a36Sopenharmony_ci	pr_err("unable to request IRQ%d for ARM PMU counters\n", irq);
68362306a36Sopenharmony_ci	return err;
68462306a36Sopenharmony_ci}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_cistatic int armpmu_get_cpu_irq(struct arm_pmu *pmu, int cpu)
68762306a36Sopenharmony_ci{
68862306a36Sopenharmony_ci	struct pmu_hw_events __percpu *hw_events = pmu->hw_events;
68962306a36Sopenharmony_ci	return per_cpu(hw_events->irq, cpu);
69062306a36Sopenharmony_ci}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cibool arm_pmu_irq_is_nmi(void)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	return has_nmi;
69562306a36Sopenharmony_ci}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci/*
69862306a36Sopenharmony_ci * PMU hardware loses all context when a CPU goes offline.
69962306a36Sopenharmony_ci * When a CPU is hotplugged back in, since some hardware registers are
70062306a36Sopenharmony_ci * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
70162306a36Sopenharmony_ci * junk values out of them.
70262306a36Sopenharmony_ci */
70362306a36Sopenharmony_cistatic int arm_perf_starting_cpu(unsigned int cpu, struct hlist_node *node)
70462306a36Sopenharmony_ci{
70562306a36Sopenharmony_ci	struct arm_pmu *pmu = hlist_entry_safe(node, struct arm_pmu, node);
70662306a36Sopenharmony_ci	int irq;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	if (!cpumask_test_cpu(cpu, &pmu->supported_cpus))
70962306a36Sopenharmony_ci		return 0;
71062306a36Sopenharmony_ci	if (pmu->reset)
71162306a36Sopenharmony_ci		pmu->reset(pmu);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	per_cpu(cpu_armpmu, cpu) = pmu;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	irq = armpmu_get_cpu_irq(pmu, cpu);
71662306a36Sopenharmony_ci	if (irq)
71762306a36Sopenharmony_ci		per_cpu(cpu_irq_ops, cpu)->enable_pmuirq(irq);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	return 0;
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_cistatic int arm_perf_teardown_cpu(unsigned int cpu, struct hlist_node *node)
72362306a36Sopenharmony_ci{
72462306a36Sopenharmony_ci	struct arm_pmu *pmu = hlist_entry_safe(node, struct arm_pmu, node);
72562306a36Sopenharmony_ci	int irq;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	if (!cpumask_test_cpu(cpu, &pmu->supported_cpus))
72862306a36Sopenharmony_ci		return 0;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	irq = armpmu_get_cpu_irq(pmu, cpu);
73162306a36Sopenharmony_ci	if (irq)
73262306a36Sopenharmony_ci		per_cpu(cpu_irq_ops, cpu)->disable_pmuirq(irq);
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	per_cpu(cpu_armpmu, cpu) = NULL;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	return 0;
73762306a36Sopenharmony_ci}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci#ifdef CONFIG_CPU_PM
74062306a36Sopenharmony_cistatic void cpu_pm_pmu_setup(struct arm_pmu *armpmu, unsigned long cmd)
74162306a36Sopenharmony_ci{
74262306a36Sopenharmony_ci	struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events);
74362306a36Sopenharmony_ci	struct perf_event *event;
74462306a36Sopenharmony_ci	int idx;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	for (idx = 0; idx < armpmu->num_events; idx++) {
74762306a36Sopenharmony_ci		event = hw_events->events[idx];
74862306a36Sopenharmony_ci		if (!event)
74962306a36Sopenharmony_ci			continue;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci		switch (cmd) {
75262306a36Sopenharmony_ci		case CPU_PM_ENTER:
75362306a36Sopenharmony_ci			/*
75462306a36Sopenharmony_ci			 * Stop and update the counter
75562306a36Sopenharmony_ci			 */
75662306a36Sopenharmony_ci			armpmu_stop(event, PERF_EF_UPDATE);
75762306a36Sopenharmony_ci			break;
75862306a36Sopenharmony_ci		case CPU_PM_EXIT:
75962306a36Sopenharmony_ci		case CPU_PM_ENTER_FAILED:
76062306a36Sopenharmony_ci			 /*
76162306a36Sopenharmony_ci			  * Restore and enable the counter.
76262306a36Sopenharmony_ci			  */
76362306a36Sopenharmony_ci			armpmu_start(event, PERF_EF_RELOAD);
76462306a36Sopenharmony_ci			break;
76562306a36Sopenharmony_ci		default:
76662306a36Sopenharmony_ci			break;
76762306a36Sopenharmony_ci		}
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ci}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_cistatic int cpu_pm_pmu_notify(struct notifier_block *b, unsigned long cmd,
77262306a36Sopenharmony_ci			     void *v)
77362306a36Sopenharmony_ci{
77462306a36Sopenharmony_ci	struct arm_pmu *armpmu = container_of(b, struct arm_pmu, cpu_pm_nb);
77562306a36Sopenharmony_ci	struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events);
77662306a36Sopenharmony_ci	bool enabled = !bitmap_empty(hw_events->used_mask, armpmu->num_events);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	if (!cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus))
77962306a36Sopenharmony_ci		return NOTIFY_DONE;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	/*
78262306a36Sopenharmony_ci	 * Always reset the PMU registers on power-up even if
78362306a36Sopenharmony_ci	 * there are no events running.
78462306a36Sopenharmony_ci	 */
78562306a36Sopenharmony_ci	if (cmd == CPU_PM_EXIT && armpmu->reset)
78662306a36Sopenharmony_ci		armpmu->reset(armpmu);
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	if (!enabled)
78962306a36Sopenharmony_ci		return NOTIFY_OK;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	switch (cmd) {
79262306a36Sopenharmony_ci	case CPU_PM_ENTER:
79362306a36Sopenharmony_ci		armpmu->stop(armpmu);
79462306a36Sopenharmony_ci		cpu_pm_pmu_setup(armpmu, cmd);
79562306a36Sopenharmony_ci		break;
79662306a36Sopenharmony_ci	case CPU_PM_EXIT:
79762306a36Sopenharmony_ci	case CPU_PM_ENTER_FAILED:
79862306a36Sopenharmony_ci		cpu_pm_pmu_setup(armpmu, cmd);
79962306a36Sopenharmony_ci		armpmu->start(armpmu);
80062306a36Sopenharmony_ci		break;
80162306a36Sopenharmony_ci	default:
80262306a36Sopenharmony_ci		return NOTIFY_DONE;
80362306a36Sopenharmony_ci	}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	return NOTIFY_OK;
80662306a36Sopenharmony_ci}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_cistatic int cpu_pm_pmu_register(struct arm_pmu *cpu_pmu)
80962306a36Sopenharmony_ci{
81062306a36Sopenharmony_ci	cpu_pmu->cpu_pm_nb.notifier_call = cpu_pm_pmu_notify;
81162306a36Sopenharmony_ci	return cpu_pm_register_notifier(&cpu_pmu->cpu_pm_nb);
81262306a36Sopenharmony_ci}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_cistatic void cpu_pm_pmu_unregister(struct arm_pmu *cpu_pmu)
81562306a36Sopenharmony_ci{
81662306a36Sopenharmony_ci	cpu_pm_unregister_notifier(&cpu_pmu->cpu_pm_nb);
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci#else
81962306a36Sopenharmony_cistatic inline int cpu_pm_pmu_register(struct arm_pmu *cpu_pmu) { return 0; }
82062306a36Sopenharmony_cistatic inline void cpu_pm_pmu_unregister(struct arm_pmu *cpu_pmu) { }
82162306a36Sopenharmony_ci#endif
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_cistatic int cpu_pmu_init(struct arm_pmu *cpu_pmu)
82462306a36Sopenharmony_ci{
82562306a36Sopenharmony_ci	int err;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	err = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_STARTING,
82862306a36Sopenharmony_ci				       &cpu_pmu->node);
82962306a36Sopenharmony_ci	if (err)
83062306a36Sopenharmony_ci		goto out;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	err = cpu_pm_pmu_register(cpu_pmu);
83362306a36Sopenharmony_ci	if (err)
83462306a36Sopenharmony_ci		goto out_unregister;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	return 0;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ciout_unregister:
83962306a36Sopenharmony_ci	cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_STARTING,
84062306a36Sopenharmony_ci					    &cpu_pmu->node);
84162306a36Sopenharmony_ciout:
84262306a36Sopenharmony_ci	return err;
84362306a36Sopenharmony_ci}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_cistatic void cpu_pmu_destroy(struct arm_pmu *cpu_pmu)
84662306a36Sopenharmony_ci{
84762306a36Sopenharmony_ci	cpu_pm_pmu_unregister(cpu_pmu);
84862306a36Sopenharmony_ci	cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_STARTING,
84962306a36Sopenharmony_ci					    &cpu_pmu->node);
85062306a36Sopenharmony_ci}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_cistruct arm_pmu *armpmu_alloc(void)
85362306a36Sopenharmony_ci{
85462306a36Sopenharmony_ci	struct arm_pmu *pmu;
85562306a36Sopenharmony_ci	int cpu;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	pmu = kzalloc(sizeof(*pmu), GFP_KERNEL);
85862306a36Sopenharmony_ci	if (!pmu)
85962306a36Sopenharmony_ci		goto out;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	pmu->hw_events = alloc_percpu_gfp(struct pmu_hw_events, GFP_KERNEL);
86262306a36Sopenharmony_ci	if (!pmu->hw_events) {
86362306a36Sopenharmony_ci		pr_info("failed to allocate per-cpu PMU data.\n");
86462306a36Sopenharmony_ci		goto out_free_pmu;
86562306a36Sopenharmony_ci	}
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	pmu->pmu = (struct pmu) {
86862306a36Sopenharmony_ci		.pmu_enable	= armpmu_enable,
86962306a36Sopenharmony_ci		.pmu_disable	= armpmu_disable,
87062306a36Sopenharmony_ci		.event_init	= armpmu_event_init,
87162306a36Sopenharmony_ci		.add		= armpmu_add,
87262306a36Sopenharmony_ci		.del		= armpmu_del,
87362306a36Sopenharmony_ci		.start		= armpmu_start,
87462306a36Sopenharmony_ci		.stop		= armpmu_stop,
87562306a36Sopenharmony_ci		.read		= armpmu_read,
87662306a36Sopenharmony_ci		.filter		= armpmu_filter,
87762306a36Sopenharmony_ci		.attr_groups	= pmu->attr_groups,
87862306a36Sopenharmony_ci		/*
87962306a36Sopenharmony_ci		 * This is a CPU PMU potentially in a heterogeneous
88062306a36Sopenharmony_ci		 * configuration (e.g. big.LITTLE) so
88162306a36Sopenharmony_ci		 * PERF_PMU_CAP_EXTENDED_HW_TYPE is required to open
88262306a36Sopenharmony_ci		 * PERF_TYPE_HARDWARE and PERF_TYPE_HW_CACHE events on a
88362306a36Sopenharmony_ci		 * specific PMU.
88462306a36Sopenharmony_ci		 */
88562306a36Sopenharmony_ci		.capabilities	= PERF_PMU_CAP_EXTENDED_REGS |
88662306a36Sopenharmony_ci				  PERF_PMU_CAP_EXTENDED_HW_TYPE,
88762306a36Sopenharmony_ci	};
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	pmu->attr_groups[ARMPMU_ATTR_GROUP_COMMON] =
89062306a36Sopenharmony_ci		&armpmu_common_attr_group;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	for_each_possible_cpu(cpu) {
89362306a36Sopenharmony_ci		struct pmu_hw_events *events;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci		events = per_cpu_ptr(pmu->hw_events, cpu);
89662306a36Sopenharmony_ci		raw_spin_lock_init(&events->pmu_lock);
89762306a36Sopenharmony_ci		events->percpu_pmu = pmu;
89862306a36Sopenharmony_ci	}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	return pmu;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ciout_free_pmu:
90362306a36Sopenharmony_ci	kfree(pmu);
90462306a36Sopenharmony_ciout:
90562306a36Sopenharmony_ci	return NULL;
90662306a36Sopenharmony_ci}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_civoid armpmu_free(struct arm_pmu *pmu)
90962306a36Sopenharmony_ci{
91062306a36Sopenharmony_ci	free_percpu(pmu->hw_events);
91162306a36Sopenharmony_ci	kfree(pmu);
91262306a36Sopenharmony_ci}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ciint armpmu_register(struct arm_pmu *pmu)
91562306a36Sopenharmony_ci{
91662306a36Sopenharmony_ci	int ret;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	ret = cpu_pmu_init(pmu);
91962306a36Sopenharmony_ci	if (ret)
92062306a36Sopenharmony_ci		return ret;
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	if (!pmu->set_event_filter)
92362306a36Sopenharmony_ci		pmu->pmu.capabilities |= PERF_PMU_CAP_NO_EXCLUDE;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	ret = perf_pmu_register(&pmu->pmu, pmu->name, -1);
92662306a36Sopenharmony_ci	if (ret)
92762306a36Sopenharmony_ci		goto out_destroy;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	pr_info("enabled with %s PMU driver, %d counters available%s\n",
93062306a36Sopenharmony_ci		pmu->name, pmu->num_events,
93162306a36Sopenharmony_ci		has_nmi ? ", using NMIs" : "");
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	kvm_host_pmu_init(pmu);
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	return 0;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ciout_destroy:
93862306a36Sopenharmony_ci	cpu_pmu_destroy(pmu);
93962306a36Sopenharmony_ci	return ret;
94062306a36Sopenharmony_ci}
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_cistatic int arm_pmu_hp_init(void)
94362306a36Sopenharmony_ci{
94462306a36Sopenharmony_ci	int ret;
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_STARTING,
94762306a36Sopenharmony_ci				      "perf/arm/pmu:starting",
94862306a36Sopenharmony_ci				      arm_perf_starting_cpu,
94962306a36Sopenharmony_ci				      arm_perf_teardown_cpu);
95062306a36Sopenharmony_ci	if (ret)
95162306a36Sopenharmony_ci		pr_err("CPU hotplug notifier for ARM PMU could not be registered: %d\n",
95262306a36Sopenharmony_ci		       ret);
95362306a36Sopenharmony_ci	return ret;
95462306a36Sopenharmony_ci}
95562306a36Sopenharmony_cisubsys_initcall(arm_pmu_hp_init);
956