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