1903b20ad6810e05bc5f7cc038257e80463e71001James Hogan/* 2903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * Meta performance counter support. 3903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * Copyright (C) 2012 Imagination Technologies Ltd 4903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * 5903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * This code is based on the sh pmu code: 6903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * Copyright (C) 2009 Paul Mundt 7903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * 8903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * and on the arm pmu code: 9903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * Copyright (C) 2009 picoChip Designs, Ltd., James Iles 10903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * Copyright (C) 2010 ARM Ltd., Will Deacon <will.deacon@arm.com> 11903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * 12903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * This file is subject to the terms and conditions of the GNU General Public 13903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * License. See the file "COPYING" in the main directory of this archive 14903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * for more details. 15903b20ad6810e05bc5f7cc038257e80463e71001James Hogan */ 16903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 17903b20ad6810e05bc5f7cc038257e80463e71001James Hogan#include <linux/atomic.h> 18903b20ad6810e05bc5f7cc038257e80463e71001James Hogan#include <linux/export.h> 19903b20ad6810e05bc5f7cc038257e80463e71001James Hogan#include <linux/init.h> 20903b20ad6810e05bc5f7cc038257e80463e71001James Hogan#include <linux/irqchip/metag.h> 21903b20ad6810e05bc5f7cc038257e80463e71001James Hogan#include <linux/perf_event.h> 22903b20ad6810e05bc5f7cc038257e80463e71001James Hogan#include <linux/slab.h> 23903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 24903b20ad6810e05bc5f7cc038257e80463e71001James Hogan#include <asm/core_reg.h> 25903b20ad6810e05bc5f7cc038257e80463e71001James Hogan#include <asm/io.h> 26903b20ad6810e05bc5f7cc038257e80463e71001James Hogan#include <asm/irq.h> 279344de1b1c64b2217f3b15508266deff2a8d6c84James Hogan#include <asm/processor.h> 28903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 29903b20ad6810e05bc5f7cc038257e80463e71001James Hogan#include "perf_event.h" 30903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 31903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic int _hw_perf_event_init(struct perf_event *); 32903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic void _hw_perf_event_destroy(struct perf_event *); 33903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 34903b20ad6810e05bc5f7cc038257e80463e71001James Hogan/* Determines which core type we are */ 35903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic struct metag_pmu *metag_pmu __read_mostly; 36903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 37903b20ad6810e05bc5f7cc038257e80463e71001James Hogan/* Processor specific data */ 38903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events); 39903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 40903b20ad6810e05bc5f7cc038257e80463e71001James Hogan/* PMU admin */ 41903b20ad6810e05bc5f7cc038257e80463e71001James Hoganconst char *perf_pmu_name(void) 42903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 43f27086f5dcb0c7e9622f724d5279e4dfe4e844a2James Hogan if (!metag_pmu) 44f27086f5dcb0c7e9622f724d5279e4dfe4e844a2James Hogan return NULL; 45903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 46f27086f5dcb0c7e9622f724d5279e4dfe4e844a2James Hogan return metag_pmu->name; 47903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 48903b20ad6810e05bc5f7cc038257e80463e71001James HoganEXPORT_SYMBOL_GPL(perf_pmu_name); 49903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 50903b20ad6810e05bc5f7cc038257e80463e71001James Hoganint perf_num_counters(void) 51903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 52903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (metag_pmu) 53903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return metag_pmu->max_events; 54903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 55903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return 0; 56903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 57903b20ad6810e05bc5f7cc038257e80463e71001James HoganEXPORT_SYMBOL_GPL(perf_num_counters); 58903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 59903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic inline int metag_pmu_initialised(void) 60903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 61903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return !!metag_pmu; 62903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 63903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 64903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic void release_pmu_hardware(void) 65903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 66903b20ad6810e05bc5f7cc038257e80463e71001James Hogan int irq; 67903b20ad6810e05bc5f7cc038257e80463e71001James Hogan unsigned int version = (metag_pmu->version & 68903b20ad6810e05bc5f7cc038257e80463e71001James Hogan (METAC_ID_MINOR_BITS | METAC_ID_REV_BITS)) >> 69903b20ad6810e05bc5f7cc038257e80463e71001James Hogan METAC_ID_REV_S; 70903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 71903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* Early cores don't have overflow interrupts */ 72903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (version < 0x0104) 73903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return; 74903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 75903b20ad6810e05bc5f7cc038257e80463e71001James Hogan irq = internal_irq_map(17); 76903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (irq >= 0) 77903b20ad6810e05bc5f7cc038257e80463e71001James Hogan free_irq(irq, (void *)1); 78903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 79903b20ad6810e05bc5f7cc038257e80463e71001James Hogan irq = internal_irq_map(16); 80903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (irq >= 0) 81903b20ad6810e05bc5f7cc038257e80463e71001James Hogan free_irq(irq, (void *)0); 82903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 83903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 84903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic int reserve_pmu_hardware(void) 85903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 86903b20ad6810e05bc5f7cc038257e80463e71001James Hogan int err = 0, irq[2]; 87903b20ad6810e05bc5f7cc038257e80463e71001James Hogan unsigned int version = (metag_pmu->version & 88903b20ad6810e05bc5f7cc038257e80463e71001James Hogan (METAC_ID_MINOR_BITS | METAC_ID_REV_BITS)) >> 89903b20ad6810e05bc5f7cc038257e80463e71001James Hogan METAC_ID_REV_S; 90903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 91903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* Early cores don't have overflow interrupts */ 92903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (version < 0x0104) 93903b20ad6810e05bc5f7cc038257e80463e71001James Hogan goto out; 94903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 95903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* 96903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * Bit 16 on HWSTATMETA is the interrupt for performance counter 0; 97903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * similarly, 17 is the interrupt for performance counter 1. 98903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * We can't (yet) interrupt on the cycle counter, because it's a 99903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * register, however it holds a 32-bit value as opposed to 24-bit. 100903b20ad6810e05bc5f7cc038257e80463e71001James Hogan */ 101903b20ad6810e05bc5f7cc038257e80463e71001James Hogan irq[0] = internal_irq_map(16); 102903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (irq[0] < 0) { 103903b20ad6810e05bc5f7cc038257e80463e71001James Hogan pr_err("unable to map internal IRQ %d\n", 16); 104903b20ad6810e05bc5f7cc038257e80463e71001James Hogan goto out; 105903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 106903b20ad6810e05bc5f7cc038257e80463e71001James Hogan err = request_irq(irq[0], metag_pmu->handle_irq, IRQF_NOBALANCING, 107903b20ad6810e05bc5f7cc038257e80463e71001James Hogan "metagpmu0", (void *)0); 108903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (err) { 109903b20ad6810e05bc5f7cc038257e80463e71001James Hogan pr_err("unable to request IRQ%d for metag PMU counters\n", 110903b20ad6810e05bc5f7cc038257e80463e71001James Hogan irq[0]); 111903b20ad6810e05bc5f7cc038257e80463e71001James Hogan goto out; 112903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 113903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 114903b20ad6810e05bc5f7cc038257e80463e71001James Hogan irq[1] = internal_irq_map(17); 115903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (irq[1] < 0) { 116903b20ad6810e05bc5f7cc038257e80463e71001James Hogan pr_err("unable to map internal IRQ %d\n", 17); 117903b20ad6810e05bc5f7cc038257e80463e71001James Hogan goto out_irq1; 118903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 119903b20ad6810e05bc5f7cc038257e80463e71001James Hogan err = request_irq(irq[1], metag_pmu->handle_irq, IRQF_NOBALANCING, 120903b20ad6810e05bc5f7cc038257e80463e71001James Hogan "metagpmu1", (void *)1); 121903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (err) { 122903b20ad6810e05bc5f7cc038257e80463e71001James Hogan pr_err("unable to request IRQ%d for metag PMU counters\n", 123903b20ad6810e05bc5f7cc038257e80463e71001James Hogan irq[1]); 124903b20ad6810e05bc5f7cc038257e80463e71001James Hogan goto out_irq1; 125903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 126903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 127903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return 0; 128903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 129903b20ad6810e05bc5f7cc038257e80463e71001James Hoganout_irq1: 130903b20ad6810e05bc5f7cc038257e80463e71001James Hogan free_irq(irq[0], (void *)0); 131903b20ad6810e05bc5f7cc038257e80463e71001James Hoganout: 132903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return err; 133903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 134903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 135903b20ad6810e05bc5f7cc038257e80463e71001James Hogan/* PMU operations */ 136903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic void metag_pmu_enable(struct pmu *pmu) 137903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 138903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 139903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 140903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic void metag_pmu_disable(struct pmu *pmu) 141903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 142903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 143903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 144903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic int metag_pmu_event_init(struct perf_event *event) 145903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 146903b20ad6810e05bc5f7cc038257e80463e71001James Hogan int err = 0; 147903b20ad6810e05bc5f7cc038257e80463e71001James Hogan atomic_t *active_events = &metag_pmu->active_events; 148903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 149903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (!metag_pmu_initialised()) { 150903b20ad6810e05bc5f7cc038257e80463e71001James Hogan err = -ENODEV; 151903b20ad6810e05bc5f7cc038257e80463e71001James Hogan goto out; 152903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 153903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 154903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (has_branch_stack(event)) 155903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return -EOPNOTSUPP; 156903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 157903b20ad6810e05bc5f7cc038257e80463e71001James Hogan event->destroy = _hw_perf_event_destroy; 158903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 159903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (!atomic_inc_not_zero(active_events)) { 160903b20ad6810e05bc5f7cc038257e80463e71001James Hogan mutex_lock(&metag_pmu->reserve_mutex); 161903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (atomic_read(active_events) == 0) 162903b20ad6810e05bc5f7cc038257e80463e71001James Hogan err = reserve_pmu_hardware(); 163903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 164903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (!err) 165903b20ad6810e05bc5f7cc038257e80463e71001James Hogan atomic_inc(active_events); 166903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 167903b20ad6810e05bc5f7cc038257e80463e71001James Hogan mutex_unlock(&metag_pmu->reserve_mutex); 168903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 169903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 170903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* Hardware and caches counters */ 171903b20ad6810e05bc5f7cc038257e80463e71001James Hogan switch (event->attr.type) { 172903b20ad6810e05bc5f7cc038257e80463e71001James Hogan case PERF_TYPE_HARDWARE: 173903b20ad6810e05bc5f7cc038257e80463e71001James Hogan case PERF_TYPE_HW_CACHE: 174f27086f5dcb0c7e9622f724d5279e4dfe4e844a2James Hogan case PERF_TYPE_RAW: 175903b20ad6810e05bc5f7cc038257e80463e71001James Hogan err = _hw_perf_event_init(event); 176903b20ad6810e05bc5f7cc038257e80463e71001James Hogan break; 177903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 178903b20ad6810e05bc5f7cc038257e80463e71001James Hogan default: 179903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return -ENOENT; 180903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 181903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 182903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (err) 183903b20ad6810e05bc5f7cc038257e80463e71001James Hogan event->destroy(event); 184903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 185903b20ad6810e05bc5f7cc038257e80463e71001James Hoganout: 186903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return err; 187903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 188903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 189903b20ad6810e05bc5f7cc038257e80463e71001James Hoganvoid metag_pmu_event_update(struct perf_event *event, 190903b20ad6810e05bc5f7cc038257e80463e71001James Hogan struct hw_perf_event *hwc, int idx) 191903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 192903b20ad6810e05bc5f7cc038257e80463e71001James Hogan u64 prev_raw_count, new_raw_count; 193903b20ad6810e05bc5f7cc038257e80463e71001James Hogan s64 delta; 194903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 195903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* 196903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * If this counter is chained, it may be that the previous counter 197903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * value has been changed beneath us. 198903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * 199903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * To get around this, we read and exchange the new raw count, then 200903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * add the delta (new - prev) to the generic counter atomically. 201903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * 202903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * Without interrupts, this is the simplest approach. 203903b20ad6810e05bc5f7cc038257e80463e71001James Hogan */ 204903b20ad6810e05bc5f7cc038257e80463e71001James Hoganagain: 205903b20ad6810e05bc5f7cc038257e80463e71001James Hogan prev_raw_count = local64_read(&hwc->prev_count); 206903b20ad6810e05bc5f7cc038257e80463e71001James Hogan new_raw_count = metag_pmu->read(idx); 207903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 208903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, 209903b20ad6810e05bc5f7cc038257e80463e71001James Hogan new_raw_count) != prev_raw_count) 210903b20ad6810e05bc5f7cc038257e80463e71001James Hogan goto again; 211903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 212903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* 213903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * Calculate the delta and add it to the counter. 214903b20ad6810e05bc5f7cc038257e80463e71001James Hogan */ 215c43ca04b5e7854b3996f84a495e4553941e76266James Hogan delta = (new_raw_count - prev_raw_count) & MAX_PERIOD; 216903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 217903b20ad6810e05bc5f7cc038257e80463e71001James Hogan local64_add(delta, &event->count); 2182033dc54e6fffac01f6129c0038c2e78102cf59aJames Hogan local64_sub(delta, &hwc->period_left); 219903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 220903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 221903b20ad6810e05bc5f7cc038257e80463e71001James Hoganint metag_pmu_event_set_period(struct perf_event *event, 222903b20ad6810e05bc5f7cc038257e80463e71001James Hogan struct hw_perf_event *hwc, int idx) 223903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 224903b20ad6810e05bc5f7cc038257e80463e71001James Hogan s64 left = local64_read(&hwc->period_left); 225903b20ad6810e05bc5f7cc038257e80463e71001James Hogan s64 period = hwc->sample_period; 226903b20ad6810e05bc5f7cc038257e80463e71001James Hogan int ret = 0; 227903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 2282033dc54e6fffac01f6129c0038c2e78102cf59aJames Hogan /* The period may have been changed */ 2292033dc54e6fffac01f6129c0038c2e78102cf59aJames Hogan if (unlikely(period != hwc->last_period)) 2302033dc54e6fffac01f6129c0038c2e78102cf59aJames Hogan left += period - hwc->last_period; 2312033dc54e6fffac01f6129c0038c2e78102cf59aJames Hogan 232903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (unlikely(left <= -period)) { 233903b20ad6810e05bc5f7cc038257e80463e71001James Hogan left = period; 234903b20ad6810e05bc5f7cc038257e80463e71001James Hogan local64_set(&hwc->period_left, left); 235903b20ad6810e05bc5f7cc038257e80463e71001James Hogan hwc->last_period = period; 236903b20ad6810e05bc5f7cc038257e80463e71001James Hogan ret = 1; 237903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 238903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 239903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (unlikely(left <= 0)) { 240903b20ad6810e05bc5f7cc038257e80463e71001James Hogan left += period; 241903b20ad6810e05bc5f7cc038257e80463e71001James Hogan local64_set(&hwc->period_left, left); 242903b20ad6810e05bc5f7cc038257e80463e71001James Hogan hwc->last_period = period; 243903b20ad6810e05bc5f7cc038257e80463e71001James Hogan ret = 1; 244903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 245903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 246903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (left > (s64)metag_pmu->max_period) 247903b20ad6810e05bc5f7cc038257e80463e71001James Hogan left = metag_pmu->max_period; 248903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 249c6ac1e6edacc7e1fb0405d61f95a797c6a712411James Hogan if (metag_pmu->write) { 250c6ac1e6edacc7e1fb0405d61f95a797c6a712411James Hogan local64_set(&hwc->prev_count, -(s32)left); 251c6ac1e6edacc7e1fb0405d61f95a797c6a712411James Hogan metag_pmu->write(idx, -left & MAX_PERIOD); 252c6ac1e6edacc7e1fb0405d61f95a797c6a712411James Hogan } 253903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 254903b20ad6810e05bc5f7cc038257e80463e71001James Hogan perf_event_update_userpage(event); 255903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 256903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return ret; 257903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 258903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 259903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic void metag_pmu_start(struct perf_event *event, int flags) 260903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 261bd83e65bfaedafef1ba21ce19c1ea7913da01becChristoph Lameter struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 262903b20ad6810e05bc5f7cc038257e80463e71001James Hogan struct hw_perf_event *hwc = &event->hw; 263903b20ad6810e05bc5f7cc038257e80463e71001James Hogan int idx = hwc->idx; 264903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 265903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (WARN_ON_ONCE(idx == -1)) 266903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return; 267903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 268903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* 269903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * We always have to reprogram the period, so ignore PERF_EF_RELOAD. 270903b20ad6810e05bc5f7cc038257e80463e71001James Hogan */ 271903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (flags & PERF_EF_RELOAD) 272903b20ad6810e05bc5f7cc038257e80463e71001James Hogan WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE)); 273903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 274903b20ad6810e05bc5f7cc038257e80463e71001James Hogan hwc->state = 0; 275903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 276903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* 277903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * Reset the period. 278903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * Some counters can't be stopped (i.e. are core global), so when the 279903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * counter was 'stopped' we merely disabled the IRQ. If we don't reset 280903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * the period, then we'll either: a) get an overflow too soon; 281903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * or b) too late if the overflow happened since disabling. 282903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * Obviously, this has little bearing on cores without the overflow 283903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * interrupt, as the performance counter resets to zero on write 284903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * anyway. 285903b20ad6810e05bc5f7cc038257e80463e71001James Hogan */ 286903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (metag_pmu->max_period) 287903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_pmu_event_set_period(event, hwc, hwc->idx); 288903b20ad6810e05bc5f7cc038257e80463e71001James Hogan cpuc->events[idx] = event; 289903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_pmu->enable(hwc, idx); 290903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 291903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 292903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic void metag_pmu_stop(struct perf_event *event, int flags) 293903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 294903b20ad6810e05bc5f7cc038257e80463e71001James Hogan struct hw_perf_event *hwc = &event->hw; 295903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 296903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* 297903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * We should always update the counter on stop; see comment above 298903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * why. 299903b20ad6810e05bc5f7cc038257e80463e71001James Hogan */ 300903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (!(hwc->state & PERF_HES_STOPPED)) { 301903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_pmu_event_update(event, hwc, hwc->idx); 302903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_pmu->disable(hwc, hwc->idx); 303903b20ad6810e05bc5f7cc038257e80463e71001James Hogan hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE; 304903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 305903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 306903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 307903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic int metag_pmu_add(struct perf_event *event, int flags) 308903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 309bd83e65bfaedafef1ba21ce19c1ea7913da01becChristoph Lameter struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 310903b20ad6810e05bc5f7cc038257e80463e71001James Hogan struct hw_perf_event *hwc = &event->hw; 311903b20ad6810e05bc5f7cc038257e80463e71001James Hogan int idx = 0, ret = 0; 312903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 313903b20ad6810e05bc5f7cc038257e80463e71001James Hogan perf_pmu_disable(event->pmu); 314903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 315903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* check whether we're counting instructions */ 316903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (hwc->config == 0x100) { 317903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (__test_and_set_bit(METAG_INST_COUNTER, 318903b20ad6810e05bc5f7cc038257e80463e71001James Hogan cpuc->used_mask)) { 319903b20ad6810e05bc5f7cc038257e80463e71001James Hogan ret = -EAGAIN; 320903b20ad6810e05bc5f7cc038257e80463e71001James Hogan goto out; 321903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 322903b20ad6810e05bc5f7cc038257e80463e71001James Hogan idx = METAG_INST_COUNTER; 323903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } else { 324903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* Check whether we have a spare counter */ 325903b20ad6810e05bc5f7cc038257e80463e71001James Hogan idx = find_first_zero_bit(cpuc->used_mask, 326903b20ad6810e05bc5f7cc038257e80463e71001James Hogan atomic_read(&metag_pmu->active_events)); 327903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (idx >= METAG_INST_COUNTER) { 328903b20ad6810e05bc5f7cc038257e80463e71001James Hogan ret = -EAGAIN; 329903b20ad6810e05bc5f7cc038257e80463e71001James Hogan goto out; 330903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 331903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 332903b20ad6810e05bc5f7cc038257e80463e71001James Hogan __set_bit(idx, cpuc->used_mask); 333903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 334903b20ad6810e05bc5f7cc038257e80463e71001James Hogan hwc->idx = idx; 335903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 336903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* Make sure the counter is disabled */ 337903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_pmu->disable(hwc, idx); 338903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 339903b20ad6810e05bc5f7cc038257e80463e71001James Hogan hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE; 340903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (flags & PERF_EF_START) 341903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_pmu_start(event, PERF_EF_RELOAD); 342903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 343903b20ad6810e05bc5f7cc038257e80463e71001James Hogan perf_event_update_userpage(event); 344903b20ad6810e05bc5f7cc038257e80463e71001James Hoganout: 345903b20ad6810e05bc5f7cc038257e80463e71001James Hogan perf_pmu_enable(event->pmu); 346903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return ret; 347903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 348903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 349903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic void metag_pmu_del(struct perf_event *event, int flags) 350903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 351bd83e65bfaedafef1ba21ce19c1ea7913da01becChristoph Lameter struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 352903b20ad6810e05bc5f7cc038257e80463e71001James Hogan struct hw_perf_event *hwc = &event->hw; 353903b20ad6810e05bc5f7cc038257e80463e71001James Hogan int idx = hwc->idx; 354903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 355903b20ad6810e05bc5f7cc038257e80463e71001James Hogan WARN_ON(idx < 0); 356903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_pmu_stop(event, PERF_EF_UPDATE); 357903b20ad6810e05bc5f7cc038257e80463e71001James Hogan cpuc->events[idx] = NULL; 358903b20ad6810e05bc5f7cc038257e80463e71001James Hogan __clear_bit(idx, cpuc->used_mask); 359903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 360903b20ad6810e05bc5f7cc038257e80463e71001James Hogan perf_event_update_userpage(event); 361903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 362903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 363903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic void metag_pmu_read(struct perf_event *event) 364903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 365903b20ad6810e05bc5f7cc038257e80463e71001James Hogan struct hw_perf_event *hwc = &event->hw; 366903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 367903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* Don't read disabled counters! */ 368903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (hwc->idx < 0) 369903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return; 370903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 371903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_pmu_event_update(event, hwc, hwc->idx); 372903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 373903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 374903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic struct pmu pmu = { 375903b20ad6810e05bc5f7cc038257e80463e71001James Hogan .pmu_enable = metag_pmu_enable, 376903b20ad6810e05bc5f7cc038257e80463e71001James Hogan .pmu_disable = metag_pmu_disable, 377903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 378903b20ad6810e05bc5f7cc038257e80463e71001James Hogan .event_init = metag_pmu_event_init, 379903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 380903b20ad6810e05bc5f7cc038257e80463e71001James Hogan .add = metag_pmu_add, 381903b20ad6810e05bc5f7cc038257e80463e71001James Hogan .del = metag_pmu_del, 382903b20ad6810e05bc5f7cc038257e80463e71001James Hogan .start = metag_pmu_start, 383903b20ad6810e05bc5f7cc038257e80463e71001James Hogan .stop = metag_pmu_stop, 384903b20ad6810e05bc5f7cc038257e80463e71001James Hogan .read = metag_pmu_read, 385903b20ad6810e05bc5f7cc038257e80463e71001James Hogan}; 386903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 387903b20ad6810e05bc5f7cc038257e80463e71001James Hogan/* Core counter specific functions */ 388903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic const int metag_general_events[] = { 389903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [PERF_COUNT_HW_CPU_CYCLES] = 0x03, 390903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [PERF_COUNT_HW_INSTRUCTIONS] = 0x100, 391903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [PERF_COUNT_HW_CACHE_REFERENCES] = -1, 392903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [PERF_COUNT_HW_CACHE_MISSES] = -1, 393903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = -1, 394903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [PERF_COUNT_HW_BRANCH_MISSES] = -1, 395903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [PERF_COUNT_HW_BUS_CYCLES] = -1, 396903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = -1, 397903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = -1, 398903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [PERF_COUNT_HW_REF_CPU_CYCLES] = -1, 399903b20ad6810e05bc5f7cc038257e80463e71001James Hogan}; 400903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 401903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic const int metag_pmu_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { 402903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(L1D)] = { 403903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_READ)] = { 404903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = 0x08, 405903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 406903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 407903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_WRITE)] = { 408903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 409903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 410903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 411903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_PREFETCH)] = { 412903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 413903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 414903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 415903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 416903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(L1I)] = { 417903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_READ)] = { 418903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = 0x09, 419903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = 0x0a, 420903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 421903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_WRITE)] = { 422903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 423903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 424903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 425903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_PREFETCH)] = { 426903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 427903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 428903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 429903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 430903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(LL)] = { 431903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_READ)] = { 432903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 433903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 434903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 435903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_WRITE)] = { 436903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 437903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 438903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 439903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_PREFETCH)] = { 440903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 441903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 442903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 443903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 444903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(DTLB)] = { 445903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_READ)] = { 446903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = 0xd0, 447903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = 0xd2, 448903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 449903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_WRITE)] = { 450903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = 0xd4, 451903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = 0xd5, 452903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 453903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_PREFETCH)] = { 454903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 455903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 456903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 457903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 458903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(ITLB)] = { 459903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_READ)] = { 460903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = 0xd1, 461903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = 0xd3, 462903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 463903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_WRITE)] = { 464903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 465903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 466903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 467903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_PREFETCH)] = { 468903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 469903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 470903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 471903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 472903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(BPU)] = { 473903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_READ)] = { 474903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 475903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 476903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 477903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_WRITE)] = { 478903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 479903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 480903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 481903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_PREFETCH)] = { 482903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 483903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 484903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 485903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 486903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(NODE)] = { 487903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_READ)] = { 488903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 489903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 490903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 491903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_WRITE)] = { 492903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 493903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 494903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 495903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(OP_PREFETCH)] = { 496903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 497903b20ad6810e05bc5f7cc038257e80463e71001James Hogan [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 498903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 499903b20ad6810e05bc5f7cc038257e80463e71001James Hogan }, 500903b20ad6810e05bc5f7cc038257e80463e71001James Hogan}; 501903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 502903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 503903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic void _hw_perf_event_destroy(struct perf_event *event) 504903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 505903b20ad6810e05bc5f7cc038257e80463e71001James Hogan atomic_t *active_events = &metag_pmu->active_events; 506903b20ad6810e05bc5f7cc038257e80463e71001James Hogan struct mutex *pmu_mutex = &metag_pmu->reserve_mutex; 507903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 508903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (atomic_dec_and_mutex_lock(active_events, pmu_mutex)) { 509903b20ad6810e05bc5f7cc038257e80463e71001James Hogan release_pmu_hardware(); 510903b20ad6810e05bc5f7cc038257e80463e71001James Hogan mutex_unlock(pmu_mutex); 511903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 512903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 513903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 514903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic int _hw_perf_cache_event(int config, int *evp) 515903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 516903b20ad6810e05bc5f7cc038257e80463e71001James Hogan unsigned long type, op, result; 517903b20ad6810e05bc5f7cc038257e80463e71001James Hogan int ev; 518903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 519903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (!metag_pmu->cache_events) 520903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return -EINVAL; 521903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 522903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* Unpack config */ 523903b20ad6810e05bc5f7cc038257e80463e71001James Hogan type = config & 0xff; 524903b20ad6810e05bc5f7cc038257e80463e71001James Hogan op = (config >> 8) & 0xff; 525903b20ad6810e05bc5f7cc038257e80463e71001James Hogan result = (config >> 16) & 0xff; 526903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 527903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (type >= PERF_COUNT_HW_CACHE_MAX || 528903b20ad6810e05bc5f7cc038257e80463e71001James Hogan op >= PERF_COUNT_HW_CACHE_OP_MAX || 529903b20ad6810e05bc5f7cc038257e80463e71001James Hogan result >= PERF_COUNT_HW_CACHE_RESULT_MAX) 530903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return -EINVAL; 531903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 532903b20ad6810e05bc5f7cc038257e80463e71001James Hogan ev = (*metag_pmu->cache_events)[type][op][result]; 533903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (ev == 0) 534903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return -EOPNOTSUPP; 535903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (ev == -1) 536903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return -EINVAL; 537903b20ad6810e05bc5f7cc038257e80463e71001James Hogan *evp = ev; 538903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return 0; 539903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 540903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 541903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic int _hw_perf_event_init(struct perf_event *event) 542903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 543903b20ad6810e05bc5f7cc038257e80463e71001James Hogan struct perf_event_attr *attr = &event->attr; 544903b20ad6810e05bc5f7cc038257e80463e71001James Hogan struct hw_perf_event *hwc = &event->hw; 545903b20ad6810e05bc5f7cc038257e80463e71001James Hogan int mapping = 0, err; 546903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 547903b20ad6810e05bc5f7cc038257e80463e71001James Hogan switch (attr->type) { 548903b20ad6810e05bc5f7cc038257e80463e71001James Hogan case PERF_TYPE_HARDWARE: 549903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (attr->config >= PERF_COUNT_HW_MAX) 550903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return -EINVAL; 551903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 552903b20ad6810e05bc5f7cc038257e80463e71001James Hogan mapping = metag_pmu->event_map(attr->config); 553903b20ad6810e05bc5f7cc038257e80463e71001James Hogan break; 554903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 555903b20ad6810e05bc5f7cc038257e80463e71001James Hogan case PERF_TYPE_HW_CACHE: 556903b20ad6810e05bc5f7cc038257e80463e71001James Hogan err = _hw_perf_cache_event(attr->config, &mapping); 557903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (err) 558903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return err; 559903b20ad6810e05bc5f7cc038257e80463e71001James Hogan break; 560f27086f5dcb0c7e9622f724d5279e4dfe4e844a2James Hogan 561f27086f5dcb0c7e9622f724d5279e4dfe4e844a2James Hogan case PERF_TYPE_RAW: 562f27086f5dcb0c7e9622f724d5279e4dfe4e844a2James Hogan mapping = attr->config; 563f27086f5dcb0c7e9622f724d5279e4dfe4e844a2James Hogan break; 564903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 565903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 566903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* Return early if the event is unsupported */ 567903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (mapping == -1) 568903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return -EINVAL; 569903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 570903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* 571903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * Don't assign an index until the event is placed into the hardware. 572903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * -1 signifies that we're still deciding where to put it. On SMP 573903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * systems each core has its own set of counters, so we can't do any 574903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * constraint checking yet. 575903b20ad6810e05bc5f7cc038257e80463e71001James Hogan */ 576903b20ad6810e05bc5f7cc038257e80463e71001James Hogan hwc->idx = -1; 577903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 578903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* Store the event encoding */ 579903b20ad6810e05bc5f7cc038257e80463e71001James Hogan hwc->config |= (unsigned long)mapping; 580903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 581903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* 582903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * For non-sampling runs, limit the sample_period to half of the 583903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * counter width. This way, the new counter value should be less 584903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * likely to overtake the previous one (unless there are IRQ latency 585903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * issues...) 586903b20ad6810e05bc5f7cc038257e80463e71001James Hogan */ 587903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (metag_pmu->max_period) { 588903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (!hwc->sample_period) { 589903b20ad6810e05bc5f7cc038257e80463e71001James Hogan hwc->sample_period = metag_pmu->max_period >> 1; 590903b20ad6810e05bc5f7cc038257e80463e71001James Hogan hwc->last_period = hwc->sample_period; 591903b20ad6810e05bc5f7cc038257e80463e71001James Hogan local64_set(&hwc->period_left, hwc->sample_period); 592903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 593903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 594903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 595903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return 0; 596903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 597903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 598903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic void metag_pmu_enable_counter(struct hw_perf_event *event, int idx) 599903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 600bd83e65bfaedafef1ba21ce19c1ea7913da01becChristoph Lameter struct cpu_hw_events *events = this_cpu_ptr(&cpu_hw_events); 601903b20ad6810e05bc5f7cc038257e80463e71001James Hogan unsigned int config = event->config; 602903b20ad6810e05bc5f7cc038257e80463e71001James Hogan unsigned int tmp = config & 0xf0; 603903b20ad6810e05bc5f7cc038257e80463e71001James Hogan unsigned long flags; 604903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 605903b20ad6810e05bc5f7cc038257e80463e71001James Hogan raw_spin_lock_irqsave(&events->pmu_lock, flags); 606903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 607903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* 608903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * Check if we're enabling the instruction counter (index of 609903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * MAX_HWEVENTS - 1) 610903b20ad6810e05bc5f7cc038257e80463e71001James Hogan */ 611903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (METAG_INST_COUNTER == idx) { 612903b20ad6810e05bc5f7cc038257e80463e71001James Hogan WARN_ONCE((config != 0x100), 613903b20ad6810e05bc5f7cc038257e80463e71001James Hogan "invalid configuration (%d) for counter (%d)\n", 614903b20ad6810e05bc5f7cc038257e80463e71001James Hogan config, idx); 6151fb4dc5c39af941d3abc597337e0ea776bfce0f2James Hogan local64_set(&event->prev_count, __core_reg_get(TXTACTCYC)); 616903b20ad6810e05bc5f7cc038257e80463e71001James Hogan goto unlock; 617903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 618903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 619903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* Check for a core internal or performance channel event. */ 620903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (tmp) { 621f27086f5dcb0c7e9622f724d5279e4dfe4e844a2James Hogan void *perf_addr; 622903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 623903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* 624903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * Anything other than a cycle count will write the low- 625903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * nibble to the correct counter register. 626903b20ad6810e05bc5f7cc038257e80463e71001James Hogan */ 627903b20ad6810e05bc5f7cc038257e80463e71001James Hogan switch (tmp) { 628903b20ad6810e05bc5f7cc038257e80463e71001James Hogan case 0xd0: 629903b20ad6810e05bc5f7cc038257e80463e71001James Hogan perf_addr = (void *)PERF_ICORE(idx); 630903b20ad6810e05bc5f7cc038257e80463e71001James Hogan break; 631903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 632903b20ad6810e05bc5f7cc038257e80463e71001James Hogan case 0xf0: 633903b20ad6810e05bc5f7cc038257e80463e71001James Hogan perf_addr = (void *)PERF_CHAN(idx); 634903b20ad6810e05bc5f7cc038257e80463e71001James Hogan break; 635f27086f5dcb0c7e9622f724d5279e4dfe4e844a2James Hogan 636f27086f5dcb0c7e9622f724d5279e4dfe4e844a2James Hogan default: 637f27086f5dcb0c7e9622f724d5279e4dfe4e844a2James Hogan perf_addr = NULL; 638f27086f5dcb0c7e9622f724d5279e4dfe4e844a2James Hogan break; 639903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 640903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 641f27086f5dcb0c7e9622f724d5279e4dfe4e844a2James Hogan if (perf_addr) 642f27086f5dcb0c7e9622f724d5279e4dfe4e844a2James Hogan metag_out32((config & 0x0f), perf_addr); 643903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 644903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* 645903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * Now we use the high nibble as the performance event to 646903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * to count. 647903b20ad6810e05bc5f7cc038257e80463e71001James Hogan */ 648903b20ad6810e05bc5f7cc038257e80463e71001James Hogan config = tmp >> 4; 649903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 650903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 651903b20ad6810e05bc5f7cc038257e80463e71001James Hogan tmp = ((config & 0xf) << 28) | 6529344de1b1c64b2217f3b15508266deff2a8d6c84James Hogan ((1 << 24) << hard_processor_id()); 653db59932f62386cdfd8510c27a83118c5e915e9eaJames Hogan if (metag_pmu->max_period) 654db59932f62386cdfd8510c27a83118c5e915e9eaJames Hogan /* 655db59932f62386cdfd8510c27a83118c5e915e9eaJames Hogan * Cores supporting overflow interrupts may have had the counter 656db59932f62386cdfd8510c27a83118c5e915e9eaJames Hogan * set to a specific value that needs preserving. 657db59932f62386cdfd8510c27a83118c5e915e9eaJames Hogan */ 658db59932f62386cdfd8510c27a83118c5e915e9eaJames Hogan tmp |= metag_in32(PERF_COUNT(idx)) & 0x00ffffff; 659c6ac1e6edacc7e1fb0405d61f95a797c6a712411James Hogan else 660c6ac1e6edacc7e1fb0405d61f95a797c6a712411James Hogan /* 661c6ac1e6edacc7e1fb0405d61f95a797c6a712411James Hogan * Older cores reset the counter on write, so prev_count needs 662c6ac1e6edacc7e1fb0405d61f95a797c6a712411James Hogan * resetting too so we can calculate a correct delta. 663c6ac1e6edacc7e1fb0405d61f95a797c6a712411James Hogan */ 664c6ac1e6edacc7e1fb0405d61f95a797c6a712411James Hogan local64_set(&event->prev_count, 0); 665db59932f62386cdfd8510c27a83118c5e915e9eaJames Hogan 666903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_out32(tmp, PERF_COUNT(idx)); 667903b20ad6810e05bc5f7cc038257e80463e71001James Hoganunlock: 668903b20ad6810e05bc5f7cc038257e80463e71001James Hogan raw_spin_unlock_irqrestore(&events->pmu_lock, flags); 669903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 670903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 671903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic void metag_pmu_disable_counter(struct hw_perf_event *event, int idx) 672903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 673bd83e65bfaedafef1ba21ce19c1ea7913da01becChristoph Lameter struct cpu_hw_events *events = this_cpu_ptr(&cpu_hw_events); 674903b20ad6810e05bc5f7cc038257e80463e71001James Hogan unsigned int tmp = 0; 675903b20ad6810e05bc5f7cc038257e80463e71001James Hogan unsigned long flags; 676903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 677903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* 678903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * The cycle counter can't be disabled per se, as it's a hardware 679903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * thread register which is always counting. We merely return if this 680903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * is the counter we're attempting to disable. 681903b20ad6810e05bc5f7cc038257e80463e71001James Hogan */ 682903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (METAG_INST_COUNTER == idx) 683903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return; 684903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 685903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* 686903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * The counter value _should_ have been read prior to disabling, 687903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * as if we're running on an early core then the value gets reset to 688903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * 0, and any read after that would be useless. On the newer cores, 689903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * however, it's better to read-modify-update this for purposes of 690903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * the overflow interrupt. 691903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * Here we remove the thread id AND the event nibble (there are at 692903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * least two events that count events that are core global and ignore 693903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * the thread id mask). This only works because we don't mix thread 694903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * performance counts, and event 0x00 requires a thread id mask! 695903b20ad6810e05bc5f7cc038257e80463e71001James Hogan */ 696903b20ad6810e05bc5f7cc038257e80463e71001James Hogan raw_spin_lock_irqsave(&events->pmu_lock, flags); 697903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 698903b20ad6810e05bc5f7cc038257e80463e71001James Hogan tmp = metag_in32(PERF_COUNT(idx)); 699903b20ad6810e05bc5f7cc038257e80463e71001James Hogan tmp &= 0x00ffffff; 700903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_out32(tmp, PERF_COUNT(idx)); 701903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 702903b20ad6810e05bc5f7cc038257e80463e71001James Hogan raw_spin_unlock_irqrestore(&events->pmu_lock, flags); 703903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 704903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 705903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic u64 metag_pmu_read_counter(int idx) 706903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 707903b20ad6810e05bc5f7cc038257e80463e71001James Hogan u32 tmp = 0; 708903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 709903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (METAG_INST_COUNTER == idx) { 7101fb4dc5c39af941d3abc597337e0ea776bfce0f2James Hogan tmp = __core_reg_get(TXTACTCYC); 711903b20ad6810e05bc5f7cc038257e80463e71001James Hogan goto out; 712903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 713903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 714903b20ad6810e05bc5f7cc038257e80463e71001James Hogan tmp = metag_in32(PERF_COUNT(idx)) & 0x00ffffff; 715903b20ad6810e05bc5f7cc038257e80463e71001James Hoganout: 716903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return tmp; 717903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 718903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 719903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic void metag_pmu_write_counter(int idx, u32 val) 720903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 721bd83e65bfaedafef1ba21ce19c1ea7913da01becChristoph Lameter struct cpu_hw_events *events = this_cpu_ptr(&cpu_hw_events); 722903b20ad6810e05bc5f7cc038257e80463e71001James Hogan u32 tmp = 0; 723903b20ad6810e05bc5f7cc038257e80463e71001James Hogan unsigned long flags; 724903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 725903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* 726903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * This _shouldn't_ happen, but if it does, then we can just 727903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * ignore the write, as the register is read-only and clear-on-write. 728903b20ad6810e05bc5f7cc038257e80463e71001James Hogan */ 729903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (METAG_INST_COUNTER == idx) 730903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return; 731903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 732903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* 733903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * We'll keep the thread mask and event id, and just update the 734903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * counter itself. Also , we should bound the value to 24-bits. 735903b20ad6810e05bc5f7cc038257e80463e71001James Hogan */ 736903b20ad6810e05bc5f7cc038257e80463e71001James Hogan raw_spin_lock_irqsave(&events->pmu_lock, flags); 737903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 738903b20ad6810e05bc5f7cc038257e80463e71001James Hogan val &= 0x00ffffff; 739903b20ad6810e05bc5f7cc038257e80463e71001James Hogan tmp = metag_in32(PERF_COUNT(idx)) & 0xff000000; 740903b20ad6810e05bc5f7cc038257e80463e71001James Hogan val |= tmp; 741903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_out32(val, PERF_COUNT(idx)); 742903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 743903b20ad6810e05bc5f7cc038257e80463e71001James Hogan raw_spin_unlock_irqrestore(&events->pmu_lock, flags); 744903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 745903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 746903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic int metag_pmu_event_map(int idx) 747903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 748903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return metag_general_events[idx]; 749903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 750903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 751903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic irqreturn_t metag_pmu_counter_overflow(int irq, void *dev) 752903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 753903b20ad6810e05bc5f7cc038257e80463e71001James Hogan int idx = (int)dev; 754bd83e65bfaedafef1ba21ce19c1ea7913da01becChristoph Lameter struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); 755903b20ad6810e05bc5f7cc038257e80463e71001James Hogan struct perf_event *event = cpuhw->events[idx]; 756903b20ad6810e05bc5f7cc038257e80463e71001James Hogan struct hw_perf_event *hwc = &event->hw; 757903b20ad6810e05bc5f7cc038257e80463e71001James Hogan struct pt_regs *regs = get_irq_regs(); 758903b20ad6810e05bc5f7cc038257e80463e71001James Hogan struct perf_sample_data sampledata; 759903b20ad6810e05bc5f7cc038257e80463e71001James Hogan unsigned long flags; 760903b20ad6810e05bc5f7cc038257e80463e71001James Hogan u32 counter = 0; 761903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 762903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* 763903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * We need to stop the core temporarily from generating another 764903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * interrupt while we disable this counter. However, we don't want 765903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * to flag the counter as free 766903b20ad6810e05bc5f7cc038257e80463e71001James Hogan */ 767903b20ad6810e05bc5f7cc038257e80463e71001James Hogan __global_lock2(flags); 768903b20ad6810e05bc5f7cc038257e80463e71001James Hogan counter = metag_in32(PERF_COUNT(idx)); 769903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_out32((counter & 0x00ffffff), PERF_COUNT(idx)); 770903b20ad6810e05bc5f7cc038257e80463e71001James Hogan __global_unlock2(flags); 771903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 772903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* Update the counts and reset the sample period */ 773903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_pmu_event_update(event, hwc, idx); 774903b20ad6810e05bc5f7cc038257e80463e71001James Hogan perf_sample_data_init(&sampledata, 0, hwc->last_period); 775903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_pmu_event_set_period(event, hwc, idx); 776903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 777903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* 778903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * Enable the counter again once core overflow processing has 779db59932f62386cdfd8510c27a83118c5e915e9eaJames Hogan * completed. Note the counter value may have been modified while it was 780db59932f62386cdfd8510c27a83118c5e915e9eaJames Hogan * inactive to set it up ready for the next interrupt. 781903b20ad6810e05bc5f7cc038257e80463e71001James Hogan */ 782db59932f62386cdfd8510c27a83118c5e915e9eaJames Hogan if (!perf_event_overflow(event, &sampledata, regs)) { 783db59932f62386cdfd8510c27a83118c5e915e9eaJames Hogan __global_lock2(flags); 784db59932f62386cdfd8510c27a83118c5e915e9eaJames Hogan counter = (counter & 0xff000000) | 785db59932f62386cdfd8510c27a83118c5e915e9eaJames Hogan (metag_in32(PERF_COUNT(idx)) & 0x00ffffff); 786903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_out32(counter, PERF_COUNT(idx)); 787db59932f62386cdfd8510c27a83118c5e915e9eaJames Hogan __global_unlock2(flags); 788db59932f62386cdfd8510c27a83118c5e915e9eaJames Hogan } 789903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 790903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return IRQ_HANDLED; 791903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 792903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 793903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic struct metag_pmu _metag_pmu = { 794903b20ad6810e05bc5f7cc038257e80463e71001James Hogan .handle_irq = metag_pmu_counter_overflow, 795903b20ad6810e05bc5f7cc038257e80463e71001James Hogan .enable = metag_pmu_enable_counter, 796903b20ad6810e05bc5f7cc038257e80463e71001James Hogan .disable = metag_pmu_disable_counter, 797903b20ad6810e05bc5f7cc038257e80463e71001James Hogan .read = metag_pmu_read_counter, 798903b20ad6810e05bc5f7cc038257e80463e71001James Hogan .write = metag_pmu_write_counter, 799903b20ad6810e05bc5f7cc038257e80463e71001James Hogan .event_map = metag_pmu_event_map, 800903b20ad6810e05bc5f7cc038257e80463e71001James Hogan .cache_events = &metag_pmu_cache_events, 801903b20ad6810e05bc5f7cc038257e80463e71001James Hogan .max_period = MAX_PERIOD, 802903b20ad6810e05bc5f7cc038257e80463e71001James Hogan .max_events = MAX_HWEVENTS, 803903b20ad6810e05bc5f7cc038257e80463e71001James Hogan}; 804903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 805903b20ad6810e05bc5f7cc038257e80463e71001James Hogan/* PMU CPU hotplug notifier */ 80654be16e7b2c96793bee4bf472409e9d31bc77c78Paul Gortmakerstatic int metag_pmu_cpu_notify(struct notifier_block *b, unsigned long action, 80754be16e7b2c96793bee4bf472409e9d31bc77c78Paul Gortmaker void *hcpu) 808903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 809903b20ad6810e05bc5f7cc038257e80463e71001James Hogan unsigned int cpu = (unsigned int)hcpu; 810903b20ad6810e05bc5f7cc038257e80463e71001James Hogan struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu); 811903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 812903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING) 813903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return NOTIFY_DONE; 814903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 815903b20ad6810e05bc5f7cc038257e80463e71001James Hogan memset(cpuc, 0, sizeof(struct cpu_hw_events)); 816903b20ad6810e05bc5f7cc038257e80463e71001James Hogan raw_spin_lock_init(&cpuc->pmu_lock); 817903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 818903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return NOTIFY_OK; 819903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 820903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 82154be16e7b2c96793bee4bf472409e9d31bc77c78Paul Gortmakerstatic struct notifier_block metag_pmu_notifier = { 822903b20ad6810e05bc5f7cc038257e80463e71001James Hogan .notifier_call = metag_pmu_cpu_notify, 823903b20ad6810e05bc5f7cc038257e80463e71001James Hogan}; 824903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 825903b20ad6810e05bc5f7cc038257e80463e71001James Hogan/* PMU Initialisation */ 826903b20ad6810e05bc5f7cc038257e80463e71001James Hoganstatic int __init init_hw_perf_events(void) 827903b20ad6810e05bc5f7cc038257e80463e71001James Hogan{ 828903b20ad6810e05bc5f7cc038257e80463e71001James Hogan int ret = 0, cpu; 829903b20ad6810e05bc5f7cc038257e80463e71001James Hogan u32 version = *(u32 *)METAC_ID; 830903b20ad6810e05bc5f7cc038257e80463e71001James Hogan int major = (version & METAC_ID_MAJOR_BITS) >> METAC_ID_MAJOR_S; 831903b20ad6810e05bc5f7cc038257e80463e71001James Hogan int min_rev = (version & (METAC_ID_MINOR_BITS | METAC_ID_REV_BITS)) 832903b20ad6810e05bc5f7cc038257e80463e71001James Hogan >> METAC_ID_REV_S; 833903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 834903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* Not a Meta 2 core, then not supported */ 835903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (0x02 > major) { 836903b20ad6810e05bc5f7cc038257e80463e71001James Hogan pr_info("no hardware counter support available\n"); 837903b20ad6810e05bc5f7cc038257e80463e71001James Hogan goto out; 838903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } else if (0x02 == major) { 839903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_pmu = &_metag_pmu; 840903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 841903b20ad6810e05bc5f7cc038257e80463e71001James Hogan if (min_rev < 0x0104) { 842903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* 843903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * A core without overflow interrupts, and clear-on- 844903b20ad6810e05bc5f7cc038257e80463e71001James Hogan * write counters. 845903b20ad6810e05bc5f7cc038257e80463e71001James Hogan */ 846903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_pmu->handle_irq = NULL; 847903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_pmu->write = NULL; 848903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_pmu->max_period = 0; 849903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 850903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 851f27086f5dcb0c7e9622f724d5279e4dfe4e844a2James Hogan metag_pmu->name = "meta2"; 852903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_pmu->version = version; 853903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_pmu->pmu = pmu; 854903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 855903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 856903b20ad6810e05bc5f7cc038257e80463e71001James Hogan pr_info("enabled with %s PMU driver, %d counters available\n", 857903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_pmu->name, metag_pmu->max_events); 858903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 8591b92722fafe2003e49ec904f33c0020ade36bd16Vince Weaver /* 8601b92722fafe2003e49ec904f33c0020ade36bd16Vince Weaver * Early cores have "limited" counters - they have no overflow 8611b92722fafe2003e49ec904f33c0020ade36bd16Vince Weaver * interrupts - and so are unable to do sampling without extra work 8621b92722fafe2003e49ec904f33c0020ade36bd16Vince Weaver * and timer assistance. 8631b92722fafe2003e49ec904f33c0020ade36bd16Vince Weaver */ 8641b92722fafe2003e49ec904f33c0020ade36bd16Vince Weaver if (metag_pmu->max_period == 0) { 8651b92722fafe2003e49ec904f33c0020ade36bd16Vince Weaver metag_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; 8661b92722fafe2003e49ec904f33c0020ade36bd16Vince Weaver } 8671b92722fafe2003e49ec904f33c0020ade36bd16Vince Weaver 868903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* Initialise the active events and reservation mutex */ 869903b20ad6810e05bc5f7cc038257e80463e71001James Hogan atomic_set(&metag_pmu->active_events, 0); 870903b20ad6810e05bc5f7cc038257e80463e71001James Hogan mutex_init(&metag_pmu->reserve_mutex); 871903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 872903b20ad6810e05bc5f7cc038257e80463e71001James Hogan /* Clear the counters */ 873903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_out32(0, PERF_COUNT(0)); 874903b20ad6810e05bc5f7cc038257e80463e71001James Hogan metag_out32(0, PERF_COUNT(1)); 875903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 876903b20ad6810e05bc5f7cc038257e80463e71001James Hogan for_each_possible_cpu(cpu) { 877903b20ad6810e05bc5f7cc038257e80463e71001James Hogan struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu); 878903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 879903b20ad6810e05bc5f7cc038257e80463e71001James Hogan memset(cpuc, 0, sizeof(struct cpu_hw_events)); 880903b20ad6810e05bc5f7cc038257e80463e71001James Hogan raw_spin_lock_init(&cpuc->pmu_lock); 881903b20ad6810e05bc5f7cc038257e80463e71001James Hogan } 882903b20ad6810e05bc5f7cc038257e80463e71001James Hogan 883903b20ad6810e05bc5f7cc038257e80463e71001James Hogan register_cpu_notifier(&metag_pmu_notifier); 88403d8e80beb7db78a13c192431205b9c83f7e0cd1Mischa Jonker ret = perf_pmu_register(&pmu, metag_pmu->name, PERF_TYPE_RAW); 885903b20ad6810e05bc5f7cc038257e80463e71001James Hoganout: 886903b20ad6810e05bc5f7cc038257e80463e71001James Hogan return ret; 887903b20ad6810e05bc5f7cc038257e80463e71001James Hogan} 888903b20ad6810e05bc5f7cc038257e80463e71001James Hoganearly_initcall(init_hw_perf_events); 889