Linux Audio

Check our new training course

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