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