File Index
Files and directories
Sign in
FILE

arm_xscale_pmu.c

File preview with syntax highlighting.

linux-6.19.14/drivers/perf/arm_xscale_pmu.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * ARMv5 [xscale] Performance counter handling code.
  4 *
  5 * Copyright (C) 2010, ARM Ltd., Will Deacon <will.deacon@arm.com>
  6 *
  7 * Based on the previous xscale OProfile code.
  8 *
  9 * There are two variants of the xscale PMU that we support:
 10 * 	- xscale1pmu: 2 event counters and a cycle counter
 11 * 	- xscale2pmu: 4 event counters and a cycle counter
 12 * The two variants share event definitions, but have different
 13 * PMU structures.
 14 */
 15
 16#include <asm/cputype.h>
 17#include <asm/irq_regs.h>
 18
 19#include <linux/of.h>
 20#include <linux/perf/arm_pmu.h>
 21#include <linux/platform_device.h>
 22
 23enum xscale_perf_types {
 24	XSCALE_PERFCTR_ICACHE_MISS		= 0x00,
 25	XSCALE_PERFCTR_ICACHE_NO_DELIVER	= 0x01,
 26	XSCALE_PERFCTR_DATA_STALL		= 0x02,
 27	XSCALE_PERFCTR_ITLB_MISS		= 0x03,
 28	XSCALE_PERFCTR_DTLB_MISS		= 0x04,
 29	XSCALE_PERFCTR_BRANCH			= 0x05,
 30	XSCALE_PERFCTR_BRANCH_MISS		= 0x06,
 31	XSCALE_PERFCTR_INSTRUCTION		= 0x07,
 32	XSCALE_PERFCTR_DCACHE_FULL_STALL	= 0x08,
 33	XSCALE_PERFCTR_DCACHE_FULL_STALL_CONTIG	= 0x09,
 34	XSCALE_PERFCTR_DCACHE_ACCESS		= 0x0A,
 35	XSCALE_PERFCTR_DCACHE_MISS		= 0x0B,
 36	XSCALE_PERFCTR_DCACHE_WRITE_BACK	= 0x0C,
 37	XSCALE_PERFCTR_PC_CHANGED		= 0x0D,
 38	XSCALE_PERFCTR_BCU_REQUEST		= 0x10,
 39	XSCALE_PERFCTR_BCU_FULL			= 0x11,
 40	XSCALE_PERFCTR_BCU_DRAIN		= 0x12,
 41	XSCALE_PERFCTR_BCU_ECC_NO_ELOG		= 0x14,
 42	XSCALE_PERFCTR_BCU_1_BIT_ERR		= 0x15,
 43	XSCALE_PERFCTR_RMW			= 0x16,
 44	/* XSCALE_PERFCTR_CCNT is not hardware defined */
 45	XSCALE_PERFCTR_CCNT			= 0xFE,
 46	XSCALE_PERFCTR_UNUSED			= 0xFF,
 47};
 48
 49enum xscale_counters {
 50	XSCALE_CYCLE_COUNTER	= 0,
 51	XSCALE_COUNTER0,
 52	XSCALE_COUNTER1,
 53	XSCALE_COUNTER2,
 54	XSCALE_COUNTER3,
 55};
 56#define XSCALE1_NUM_COUNTERS	3
 57#define XSCALE2_NUM_COUNTERS	5
 58
 59static const unsigned xscale_perf_map[PERF_COUNT_HW_MAX] = {
 60	PERF_MAP_ALL_UNSUPPORTED,
 61	[PERF_COUNT_HW_CPU_CYCLES]		= XSCALE_PERFCTR_CCNT,
 62	[PERF_COUNT_HW_INSTRUCTIONS]		= XSCALE_PERFCTR_INSTRUCTION,
 63	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS]	= XSCALE_PERFCTR_BRANCH,
 64	[PERF_COUNT_HW_BRANCH_MISSES]		= XSCALE_PERFCTR_BRANCH_MISS,
 65	[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND]	= XSCALE_PERFCTR_ICACHE_NO_DELIVER,
 66};
 67
 68static const unsigned xscale_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
 69					   [PERF_COUNT_HW_CACHE_OP_MAX]
 70					   [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
 71	PERF_CACHE_MAP_ALL_UNSUPPORTED,
 72
 73	[C(L1D)][C(OP_READ)][C(RESULT_ACCESS)]	= XSCALE_PERFCTR_DCACHE_ACCESS,
 74	[C(L1D)][C(OP_READ)][C(RESULT_MISS)]	= XSCALE_PERFCTR_DCACHE_MISS,
 75	[C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)]	= XSCALE_PERFCTR_DCACHE_ACCESS,
 76	[C(L1D)][C(OP_WRITE)][C(RESULT_MISS)]	= XSCALE_PERFCTR_DCACHE_MISS,
 77
 78	[C(L1I)][C(OP_READ)][C(RESULT_MISS)]	= XSCALE_PERFCTR_ICACHE_MISS,
 79
 80	[C(DTLB)][C(OP_READ)][C(RESULT_MISS)]	= XSCALE_PERFCTR_DTLB_MISS,
 81	[C(DTLB)][C(OP_WRITE)][C(RESULT_MISS)]	= XSCALE_PERFCTR_DTLB_MISS,
 82
 83	[C(ITLB)][C(OP_READ)][C(RESULT_MISS)]	= XSCALE_PERFCTR_ITLB_MISS,
 84	[C(ITLB)][C(OP_WRITE)][C(RESULT_MISS)]	= XSCALE_PERFCTR_ITLB_MISS,
 85};
 86
 87#define	XSCALE_PMU_ENABLE	0x001
 88#define XSCALE_PMN_RESET	0x002
 89#define	XSCALE_CCNT_RESET	0x004
 90#define	XSCALE_PMU_RESET	(CCNT_RESET | PMN_RESET)
 91#define XSCALE_PMU_CNT64	0x008
 92
 93#define XSCALE1_OVERFLOWED_MASK	0x700
 94#define XSCALE1_CCOUNT_OVERFLOW	0x400
 95#define XSCALE1_COUNT0_OVERFLOW	0x100
 96#define XSCALE1_COUNT1_OVERFLOW	0x200
 97#define XSCALE1_CCOUNT_INT_EN	0x040
 98#define XSCALE1_COUNT0_INT_EN	0x010
 99#define XSCALE1_COUNT1_INT_EN	0x020
100#define XSCALE1_COUNT0_EVT_SHFT	12
101#define XSCALE1_COUNT0_EVT_MASK	(0xff << XSCALE1_COUNT0_EVT_SHFT)
102#define XSCALE1_COUNT1_EVT_SHFT	20
103#define XSCALE1_COUNT1_EVT_MASK	(0xff << XSCALE1_COUNT1_EVT_SHFT)
104
105static inline u32
106xscale1pmu_read_pmnc(void)
107{
108	u32 val;
109	asm volatile("mrc p14, 0, %0, c0, c0, 0" : "=r" (val));
110	return val;
111}
112
113static inline void
114xscale1pmu_write_pmnc(u32 val)
115{
116	/* upper 4bits and 7, 11 are write-as-0 */
117	val &= 0xffff77f;
118	asm volatile("mcr p14, 0, %0, c0, c0, 0" : : "r" (val));
119}
120
121static inline int
122xscale1_pmnc_counter_has_overflowed(unsigned long pmnc,
123					enum xscale_counters counter)
124{
125	int ret = 0;
126
127	switch (counter) {
128	case XSCALE_CYCLE_COUNTER:
129		ret = pmnc & XSCALE1_CCOUNT_OVERFLOW;
130		break;
131	case XSCALE_COUNTER0:
132		ret = pmnc & XSCALE1_COUNT0_OVERFLOW;
133		break;
134	case XSCALE_COUNTER1:
135		ret = pmnc & XSCALE1_COUNT1_OVERFLOW;
136		break;
137	default:
138		WARN_ONCE(1, "invalid counter number (%d)\n", counter);
139	}
140
141	return ret;
142}
143
144static irqreturn_t
145xscale1pmu_handle_irq(struct arm_pmu *cpu_pmu)
146{
147	unsigned long pmnc;
148	struct perf_sample_data data;
149	struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events);
150	struct pt_regs *regs;
151	int idx;
152
153	/*
154	 * NOTE: there's an A stepping erratum that states if an overflow
155	 *       bit already exists and another occurs, the previous
156	 *       Overflow bit gets cleared. There's no workaround.
157	 *	 Fixed in B stepping or later.
158	 */
159	pmnc = xscale1pmu_read_pmnc();
160
161	/*
162	 * Write the value back to clear the overflow flags. Overflow
163	 * flags remain in pmnc for use below. We also disable the PMU
164	 * while we process the interrupt.
165	 */
166	xscale1pmu_write_pmnc(pmnc & ~XSCALE_PMU_ENABLE);
167
168	if (!(pmnc & XSCALE1_OVERFLOWED_MASK))
169		return IRQ_NONE;
170
171	regs = get_irq_regs();
172
173	for_each_set_bit(idx, cpu_pmu->cntr_mask, XSCALE1_NUM_COUNTERS) {
174		struct perf_event *event = cpuc->events[idx];
175		struct hw_perf_event *hwc;
176
177		if (!event)
178			continue;
179
180		if (!xscale1_pmnc_counter_has_overflowed(pmnc, idx))
181			continue;
182
183		hwc = &event->hw;
184		armpmu_event_update(event);
185		perf_sample_data_init(&data, 0, hwc->last_period);
186		if (!armpmu_event_set_period(event))
187			continue;
188
189		perf_event_overflow(event, &data, regs);
190	}
191
192	irq_work_run();
193
194	/*
195	 * Re-enable the PMU.
196	 */
197	pmnc = xscale1pmu_read_pmnc() | XSCALE_PMU_ENABLE;
198	xscale1pmu_write_pmnc(pmnc);
199
200	return IRQ_HANDLED;
201}
202
203static void xscale1pmu_enable_event(struct perf_event *event)
204{
205	unsigned long val, mask, evt;
206	struct hw_perf_event *hwc = &event->hw;
207	int idx = hwc->idx;
208
209	switch (idx) {
210	case XSCALE_CYCLE_COUNTER:
211		mask = 0;
212		evt = XSCALE1_CCOUNT_INT_EN;
213		break;
214	case XSCALE_COUNTER0:
215		mask = XSCALE1_COUNT0_EVT_MASK;
216		evt = (hwc->config_base << XSCALE1_COUNT0_EVT_SHFT) |
217			XSCALE1_COUNT0_INT_EN;
218		break;
219	case XSCALE_COUNTER1:
220		mask = XSCALE1_COUNT1_EVT_MASK;
221		evt = (hwc->config_base << XSCALE1_COUNT1_EVT_SHFT) |
222			XSCALE1_COUNT1_INT_EN;
223		break;
224	default:
225		WARN_ONCE(1, "invalid counter number (%d)\n", idx);
226		return;
227	}
228
229	val = xscale1pmu_read_pmnc();
230	val &= ~mask;
231	val |= evt;
232	xscale1pmu_write_pmnc(val);
233}
234
235static void xscale1pmu_disable_event(struct perf_event *event)
236{
237	unsigned long val, mask, evt;
238	struct hw_perf_event *hwc = &event->hw;
239	int idx = hwc->idx;
240
241	switch (idx) {
242	case XSCALE_CYCLE_COUNTER:
243		mask = XSCALE1_CCOUNT_INT_EN;
244		evt = 0;
245		break;
246	case XSCALE_COUNTER0:
247		mask = XSCALE1_COUNT0_INT_EN | XSCALE1_COUNT0_EVT_MASK;
248		evt = XSCALE_PERFCTR_UNUSED << XSCALE1_COUNT0_EVT_SHFT;
249		break;
250	case XSCALE_COUNTER1:
251		mask = XSCALE1_COUNT1_INT_EN | XSCALE1_COUNT1_EVT_MASK;
252		evt = XSCALE_PERFCTR_UNUSED << XSCALE1_COUNT1_EVT_SHFT;
253		break;
254	default:
255		WARN_ONCE(1, "invalid counter number (%d)\n", idx);
256		return;
257	}
258
259	val = xscale1pmu_read_pmnc();
260	val &= ~mask;
261	val |= evt;
262	xscale1pmu_write_pmnc(val);
263}
264
265static int
266xscale1pmu_get_event_idx(struct pmu_hw_events *cpuc,
267				struct perf_event *event)
268{
269	struct hw_perf_event *hwc = &event->hw;
270	if (XSCALE_PERFCTR_CCNT == hwc->config_base) {
271		if (test_and_set_bit(XSCALE_CYCLE_COUNTER, cpuc->used_mask))
272			return -EAGAIN;
273
274		return XSCALE_CYCLE_COUNTER;
275	} else {
276		if (!test_and_set_bit(XSCALE_COUNTER1, cpuc->used_mask))
277			return XSCALE_COUNTER1;
278
279		if (!test_and_set_bit(XSCALE_COUNTER0, cpuc->used_mask))
280			return XSCALE_COUNTER0;
281
282		return -EAGAIN;
283	}
284}
285
286static void xscalepmu_clear_event_idx(struct pmu_hw_events *cpuc,
287				     struct perf_event *event)
288{
289	clear_bit(event->hw.idx, cpuc->used_mask);
290}
291
292static void xscale1pmu_start(struct arm_pmu *cpu_pmu)
293{
294	unsigned long val;
295
296	val = xscale1pmu_read_pmnc();
297	val |= XSCALE_PMU_ENABLE;
298	xscale1pmu_write_pmnc(val);
299}
300
301static void xscale1pmu_stop(struct arm_pmu *cpu_pmu)
302{
303	unsigned long val;
304
305	val = xscale1pmu_read_pmnc();
306	val &= ~XSCALE_PMU_ENABLE;
307	xscale1pmu_write_pmnc(val);
308}
309
310static inline u64 xscale1pmu_read_counter(struct perf_event *event)
311{
312	struct hw_perf_event *hwc = &event->hw;
313	int counter = hwc->idx;
314	u32 val = 0;
315
316	switch (counter) {
317	case XSCALE_CYCLE_COUNTER:
318		asm volatile("mrc p14, 0, %0, c1, c0, 0" : "=r" (val));
319		break;
320	case XSCALE_COUNTER0:
321		asm volatile("mrc p14, 0, %0, c2, c0, 0" : "=r" (val));
322		break;
323	case XSCALE_COUNTER1:
324		asm volatile("mrc p14, 0, %0, c3, c0, 0" : "=r" (val));
325		break;
326	}
327
328	return val;
329}
330
331static inline void xscale1pmu_write_counter(struct perf_event *event, u64 val)
332{
333	struct hw_perf_event *hwc = &event->hw;
334	int counter = hwc->idx;
335
336	switch (counter) {
337	case XSCALE_CYCLE_COUNTER:
338		asm volatile("mcr p14, 0, %0, c1, c0, 0" : : "r" (val));
339		break;
340	case XSCALE_COUNTER0:
341		asm volatile("mcr p14, 0, %0, c2, c0, 0" : : "r" (val));
342		break;
343	case XSCALE_COUNTER1:
344		asm volatile("mcr p14, 0, %0, c3, c0, 0" : : "r" (val));
345		break;
346	}
347}
348
349static int xscale_map_event(struct perf_event *event)
350{
351	return armpmu_map_event(event, &xscale_perf_map,
352				&xscale_perf_cache_map, 0xFF);
353}
354
355static int xscale1pmu_init(struct arm_pmu *cpu_pmu)
356{
357	cpu_pmu->name		= "armv5_xscale1";
358	cpu_pmu->handle_irq	= xscale1pmu_handle_irq;
359	cpu_pmu->enable		= xscale1pmu_enable_event;
360	cpu_pmu->disable	= xscale1pmu_disable_event;
361	cpu_pmu->read_counter	= xscale1pmu_read_counter;
362	cpu_pmu->write_counter	= xscale1pmu_write_counter;
363	cpu_pmu->get_event_idx	= xscale1pmu_get_event_idx;
364	cpu_pmu->clear_event_idx = xscalepmu_clear_event_idx;
365	cpu_pmu->start		= xscale1pmu_start;
366	cpu_pmu->stop		= xscale1pmu_stop;
367	cpu_pmu->map_event	= xscale_map_event;
368
369	bitmap_set(cpu_pmu->cntr_mask, 0, XSCALE1_NUM_COUNTERS);
370
371	return 0;
372}
373
374#define XSCALE2_OVERFLOWED_MASK	0x01f
375#define XSCALE2_CCOUNT_OVERFLOW	0x001
376#define XSCALE2_COUNT0_OVERFLOW	0x002
377#define XSCALE2_COUNT1_OVERFLOW	0x004
378#define XSCALE2_COUNT2_OVERFLOW	0x008
379#define XSCALE2_COUNT3_OVERFLOW	0x010
380#define XSCALE2_CCOUNT_INT_EN	0x001
381#define XSCALE2_COUNT0_INT_EN	0x002
382#define XSCALE2_COUNT1_INT_EN	0x004
383#define XSCALE2_COUNT2_INT_EN	0x008
384#define XSCALE2_COUNT3_INT_EN	0x010
385#define XSCALE2_COUNT0_EVT_SHFT	0
386#define XSCALE2_COUNT0_EVT_MASK	(0xff << XSCALE2_COUNT0_EVT_SHFT)
387#define XSCALE2_COUNT1_EVT_SHFT	8
388#define XSCALE2_COUNT1_EVT_MASK	(0xff << XSCALE2_COUNT1_EVT_SHFT)
389#define XSCALE2_COUNT2_EVT_SHFT	16
390#define XSCALE2_COUNT2_EVT_MASK	(0xff << XSCALE2_COUNT2_EVT_SHFT)
391#define XSCALE2_COUNT3_EVT_SHFT	24
392#define XSCALE2_COUNT3_EVT_MASK	(0xff << XSCALE2_COUNT3_EVT_SHFT)
393
394static inline u32
395xscale2pmu_read_pmnc(void)
396{
397	u32 val;
398	asm volatile("mrc p14, 0, %0, c0, c1, 0" : "=r" (val));
399	/* bits 1-2 and 4-23 are read-unpredictable */
400	return val & 0xff000009;
401}
402
403static inline void
404xscale2pmu_write_pmnc(u32 val)
405{
406	/* bits 4-23 are write-as-0, 24-31 are write ignored */
407	val &= 0xf;
408	asm volatile("mcr p14, 0, %0, c0, c1, 0" : : "r" (val));
409}
410
411static inline u32
412xscale2pmu_read_overflow_flags(void)
413{
414	u32 val;
415	asm volatile("mrc p14, 0, %0, c5, c1, 0" : "=r" (val));
416	return val;
417}
418
419static inline void
420xscale2pmu_write_overflow_flags(u32 val)
421{
422	asm volatile("mcr p14, 0, %0, c5, c1, 0" : : "r" (val));
423}
424
425static inline u32
426xscale2pmu_read_event_select(void)
427{
428	u32 val;
429	asm volatile("mrc p14, 0, %0, c8, c1, 0" : "=r" (val));
430	return val;
431}
432
433static inline void
434xscale2pmu_write_event_select(u32 val)
435{
436	asm volatile("mcr p14, 0, %0, c8, c1, 0" : : "r"(val));
437}
438
439static inline u32
440xscale2pmu_read_int_enable(void)
441{
442	u32 val;
443	asm volatile("mrc p14, 0, %0, c4, c1, 0" : "=r" (val));
444	return val;
445}
446
447static void
448xscale2pmu_write_int_enable(u32 val)
449{
450	asm volatile("mcr p14, 0, %0, c4, c1, 0" : : "r" (val));
451}
452
453static inline int
454xscale2_pmnc_counter_has_overflowed(unsigned long of_flags,
455					enum xscale_counters counter)
456{
457	int ret = 0;
458
459	switch (counter) {
460	case XSCALE_CYCLE_COUNTER:
461		ret = of_flags & XSCALE2_CCOUNT_OVERFLOW;
462		break;
463	case XSCALE_COUNTER0:
464		ret = of_flags & XSCALE2_COUNT0_OVERFLOW;
465		break;
466	case XSCALE_COUNTER1:
467		ret = of_flags & XSCALE2_COUNT1_OVERFLOW;
468		break;
469	case XSCALE_COUNTER2:
470		ret = of_flags & XSCALE2_COUNT2_OVERFLOW;
471		break;
472	case XSCALE_COUNTER3:
473		ret = of_flags & XSCALE2_COUNT3_OVERFLOW;
474		break;
475	default:
476		WARN_ONCE(1, "invalid counter number (%d)\n", counter);
477	}
478
479	return ret;
480}
481
482static irqreturn_t
483xscale2pmu_handle_irq(struct arm_pmu *cpu_pmu)
484{
485	unsigned long pmnc, of_flags;
486	struct perf_sample_data data;
487	struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events);
488	struct pt_regs *regs;
489	int idx;
490
491	/* Disable the PMU. */
492	pmnc = xscale2pmu_read_pmnc();
493	xscale2pmu_write_pmnc(pmnc & ~XSCALE_PMU_ENABLE);
494
495	/* Check the overflow flag register. */
496	of_flags = xscale2pmu_read_overflow_flags();
497	if (!(of_flags & XSCALE2_OVERFLOWED_MASK))
498		return IRQ_NONE;
499
500	/* Clear the overflow bits. */
501	xscale2pmu_write_overflow_flags(of_flags);
502
503	regs = get_irq_regs();
504
505	for_each_set_bit(idx, cpu_pmu->cntr_mask, XSCALE2_NUM_COUNTERS) {
506		struct perf_event *event = cpuc->events[idx];
507		struct hw_perf_event *hwc;
508
509		if (!event)
510			continue;
511
512		if (!xscale2_pmnc_counter_has_overflowed(of_flags, idx))
513			continue;
514
515		hwc = &event->hw;
516		armpmu_event_update(event);
517		perf_sample_data_init(&data, 0, hwc->last_period);
518		if (!armpmu_event_set_period(event))
519			continue;
520
521		perf_event_overflow(event, &data, regs);
522	}
523
524	irq_work_run();
525
526	/*
527	 * Re-enable the PMU.
528	 */
529	pmnc = xscale2pmu_read_pmnc() | XSCALE_PMU_ENABLE;
530	xscale2pmu_write_pmnc(pmnc);
531
532	return IRQ_HANDLED;
533}
534
535static void xscale2pmu_enable_event(struct perf_event *event)
536{
537	unsigned long ien, evtsel;
538	struct hw_perf_event *hwc = &event->hw;
539	int idx = hwc->idx;
540
541	ien = xscale2pmu_read_int_enable();
542	evtsel = xscale2pmu_read_event_select();
543
544	switch (idx) {
545	case XSCALE_CYCLE_COUNTER:
546		ien |= XSCALE2_CCOUNT_INT_EN;
547		break;
548	case XSCALE_COUNTER0:
549		ien |= XSCALE2_COUNT0_INT_EN;
550		evtsel &= ~XSCALE2_COUNT0_EVT_MASK;
551		evtsel |= hwc->config_base << XSCALE2_COUNT0_EVT_SHFT;
552		break;
553	case XSCALE_COUNTER1:
554		ien |= XSCALE2_COUNT1_INT_EN;
555		evtsel &= ~XSCALE2_COUNT1_EVT_MASK;
556		evtsel |= hwc->config_base << XSCALE2_COUNT1_EVT_SHFT;
557		break;
558	case XSCALE_COUNTER2:
559		ien |= XSCALE2_COUNT2_INT_EN;
560		evtsel &= ~XSCALE2_COUNT2_EVT_MASK;
561		evtsel |= hwc->config_base << XSCALE2_COUNT2_EVT_SHFT;
562		break;
563	case XSCALE_COUNTER3:
564		ien |= XSCALE2_COUNT3_INT_EN;
565		evtsel &= ~XSCALE2_COUNT3_EVT_MASK;
566		evtsel |= hwc->config_base << XSCALE2_COUNT3_EVT_SHFT;
567		break;
568	default:
569		WARN_ONCE(1, "invalid counter number (%d)\n", idx);
570		return;
571	}
572
573	xscale2pmu_write_event_select(evtsel);
574	xscale2pmu_write_int_enable(ien);
575}
576
577static void xscale2pmu_disable_event(struct perf_event *event)
578{
579	unsigned long ien, evtsel, of_flags;
580	struct hw_perf_event *hwc = &event->hw;
581	int idx = hwc->idx;
582
583	ien = xscale2pmu_read_int_enable();
584	evtsel = xscale2pmu_read_event_select();
585
586	switch (idx) {
587	case XSCALE_CYCLE_COUNTER:
588		ien &= ~XSCALE2_CCOUNT_INT_EN;
589		of_flags = XSCALE2_CCOUNT_OVERFLOW;
590		break;
591	case XSCALE_COUNTER0:
592		ien &= ~XSCALE2_COUNT0_INT_EN;
593		evtsel &= ~XSCALE2_COUNT0_EVT_MASK;
594		evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT0_EVT_SHFT;
595		of_flags = XSCALE2_COUNT0_OVERFLOW;
596		break;
597	case XSCALE_COUNTER1:
598		ien &= ~XSCALE2_COUNT1_INT_EN;
599		evtsel &= ~XSCALE2_COUNT1_EVT_MASK;
600		evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT1_EVT_SHFT;
601		of_flags = XSCALE2_COUNT1_OVERFLOW;
602		break;
603	case XSCALE_COUNTER2:
604		ien &= ~XSCALE2_COUNT2_INT_EN;
605		evtsel &= ~XSCALE2_COUNT2_EVT_MASK;
606		evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT2_EVT_SHFT;
607		of_flags = XSCALE2_COUNT2_OVERFLOW;
608		break;
609	case XSCALE_COUNTER3:
610		ien &= ~XSCALE2_COUNT3_INT_EN;
611		evtsel &= ~XSCALE2_COUNT3_EVT_MASK;
612		evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT3_EVT_SHFT;
613		of_flags = XSCALE2_COUNT3_OVERFLOW;
614		break;
615	default:
616		WARN_ONCE(1, "invalid counter number (%d)\n", idx);
617		return;
618	}
619
620	xscale2pmu_write_event_select(evtsel);
621	xscale2pmu_write_int_enable(ien);
622	xscale2pmu_write_overflow_flags(of_flags);
623}
624
625static int
626xscale2pmu_get_event_idx(struct pmu_hw_events *cpuc,
627				struct perf_event *event)
628{
629	int idx = xscale1pmu_get_event_idx(cpuc, event);
630	if (idx >= 0)
631		goto out;
632
633	if (!test_and_set_bit(XSCALE_COUNTER3, cpuc->used_mask))
634		idx = XSCALE_COUNTER3;
635	else if (!test_and_set_bit(XSCALE_COUNTER2, cpuc->used_mask))
636		idx = XSCALE_COUNTER2;
637out:
638	return idx;
639}
640
641static void xscale2pmu_start(struct arm_pmu *cpu_pmu)
642{
643	unsigned long val;
644
645	val = xscale2pmu_read_pmnc() & ~XSCALE_PMU_CNT64;
646	val |= XSCALE_PMU_ENABLE;
647	xscale2pmu_write_pmnc(val);
648}
649
650static void xscale2pmu_stop(struct arm_pmu *cpu_pmu)
651{
652	unsigned long val;
653
654	val = xscale2pmu_read_pmnc();
655	val &= ~XSCALE_PMU_ENABLE;
656	xscale2pmu_write_pmnc(val);
657}
658
659static inline u64 xscale2pmu_read_counter(struct perf_event *event)
660{
661	struct hw_perf_event *hwc = &event->hw;
662	int counter = hwc->idx;
663	u32 val = 0;
664
665	switch (counter) {
666	case XSCALE_CYCLE_COUNTER:
667		asm volatile("mrc p14, 0, %0, c1, c1, 0" : "=r" (val));
668		break;
669	case XSCALE_COUNTER0:
670		asm volatile("mrc p14, 0, %0, c0, c2, 0" : "=r" (val));
671		break;
672	case XSCALE_COUNTER1:
673		asm volatile("mrc p14, 0, %0, c1, c2, 0" : "=r" (val));
674		break;
675	case XSCALE_COUNTER2:
676		asm volatile("mrc p14, 0, %0, c2, c2, 0" : "=r" (val));
677		break;
678	case XSCALE_COUNTER3:
679		asm volatile("mrc p14, 0, %0, c3, c2, 0" : "=r" (val));
680		break;
681	}
682
683	return val;
684}
685
686static inline void xscale2pmu_write_counter(struct perf_event *event, u64 val)
687{
688	struct hw_perf_event *hwc = &event->hw;
689	int counter = hwc->idx;
690
691	switch (counter) {
692	case XSCALE_CYCLE_COUNTER:
693		asm volatile("mcr p14, 0, %0, c1, c1, 0" : : "r" (val));
694		break;
695	case XSCALE_COUNTER0:
696		asm volatile("mcr p14, 0, %0, c0, c2, 0" : : "r" (val));
697		break;
698	case XSCALE_COUNTER1:
699		asm volatile("mcr p14, 0, %0, c1, c2, 0" : : "r" (val));
700		break;
701	case XSCALE_COUNTER2:
702		asm volatile("mcr p14, 0, %0, c2, c2, 0" : : "r" (val));
703		break;
704	case XSCALE_COUNTER3:
705		asm volatile("mcr p14, 0, %0, c3, c2, 0" : : "r" (val));
706		break;
707	}
708}
709
710static int xscale2pmu_init(struct arm_pmu *cpu_pmu)
711{
712	cpu_pmu->name		= "armv5_xscale2";
713	cpu_pmu->handle_irq	= xscale2pmu_handle_irq;
714	cpu_pmu->enable		= xscale2pmu_enable_event;
715	cpu_pmu->disable	= xscale2pmu_disable_event;
716	cpu_pmu->read_counter	= xscale2pmu_read_counter;
717	cpu_pmu->write_counter	= xscale2pmu_write_counter;
718	cpu_pmu->get_event_idx	= xscale2pmu_get_event_idx;
719	cpu_pmu->clear_event_idx = xscalepmu_clear_event_idx;
720	cpu_pmu->start		= xscale2pmu_start;
721	cpu_pmu->stop		= xscale2pmu_stop;
722	cpu_pmu->map_event	= xscale_map_event;
723
724	bitmap_set(cpu_pmu->cntr_mask, 0, XSCALE2_NUM_COUNTERS);
725
726	return 0;
727}
728
729static const struct pmu_probe_info xscale_pmu_probe_table[] = {
730	XSCALE_PMU_PROBE(ARM_CPU_XSCALE_ARCH_V1, xscale1pmu_init),
731	XSCALE_PMU_PROBE(ARM_CPU_XSCALE_ARCH_V2, xscale2pmu_init),
732	{ /* sentinel value */ }
733};
734
735static int xscale_pmu_device_probe(struct platform_device *pdev)
736{
737	return arm_pmu_device_probe(pdev, NULL, xscale_pmu_probe_table);
738}
739
740static struct platform_driver xscale_pmu_driver = {
741	.driver		= {
742		.name	= "xscale-pmu",
743	},
744	.probe		= xscale_pmu_device_probe,
745};
746
747builtin_platform_driver(xscale_pmu_driver);
~/ Read-only file preview.