2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
11 /* gator_events_perf_pmu.c is used if perf is supported */
12 #if GATOR_NO_PERF_SUPPORT
14 static const char *pmnc_name;
19 #define PMCR_E (1 << 0) /* Enable */
20 #define PMCR_P (1 << 1) /* Count reset */
21 #define PMCR_C (1 << 2) /* Cycle counter reset */
22 #define PMCR_OFL_PMN0 (1 << 8) /* Count reg 0 overflow */
23 #define PMCR_OFL_PMN1 (1 << 9) /* Count reg 1 overflow */
24 #define PMCR_OFL_CCNT (1 << 10) /* Cycle counter overflow */
29 #define CNTMAX (CCNT+1)
31 static int pmnc_counters;
32 static unsigned long pmnc_enabled[CNTMAX];
33 static unsigned long pmnc_event[CNTMAX];
34 static unsigned long pmnc_key[CNTMAX];
36 static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
38 static inline void armv6_pmnc_write(u32 val)
40 /* upper 4bits and 7, 11 are write-as-0 */
42 asm volatile("mcr p15, 0, %0, c15, c12, 0" : : "r" (val));
45 static inline u32 armv6_pmnc_read(void)
49 asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (val));
53 static void armv6_pmnc_reset_counter(unsigned int cnt)
59 asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r" (val));
62 asm volatile("mcr p15, 0, %0, c15, c12, 2" : : "r" (val));
65 asm volatile("mcr p15, 0, %0, c15, c12, 3" : : "r" (val));
70 int gator_events_armv6_create_files(struct super_block *sb, struct dentry *root)
77 for (i = PMN0; i <= CCNT; i++) {
81 snprintf(buf, sizeof(buf), "ARM_%s_ccnt", pmnc_name);
83 snprintf(buf, sizeof(buf), "ARM_%s_cnt%d", pmnc_name, i);
84 dir = gatorfs_mkdir(sb, root, buf);
87 gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
88 gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
90 gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
96 static int gator_events_armv6_online(int **buffer, bool migrate)
98 unsigned int cnt, len = 0, cpu = smp_processor_id();
101 if (armv6_pmnc_read() & PMCR_E)
102 armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
104 /* initialize PMNC, reset overflow, D bit, C bit and P bit. */
105 armv6_pmnc_write(PMCR_OFL_PMN0 | PMCR_OFL_PMN1 | PMCR_OFL_CCNT |
108 /* configure control register */
109 for (pmnc = 0, cnt = PMN0; cnt <= CCNT; cnt++) {
112 if (!pmnc_enabled[cnt])
115 event = pmnc_event[cnt] & 255;
117 /* Set event (if destined for PMNx counters) */
120 else if (cnt == PMN1)
124 armv6_pmnc_reset_counter(cnt);
126 armv6_pmnc_write(pmnc | PMCR_E);
128 /* return zero values, no need to read as the counters were just reset */
129 for (cnt = PMN0; cnt <= CCNT; cnt++) {
130 if (pmnc_enabled[cnt]) {
131 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
132 per_cpu(perfCnt, cpu)[len++] = 0;
137 *buffer = per_cpu(perfCnt, cpu);
142 static int gator_events_armv6_offline(int **buffer, bool migrate)
146 armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
147 for (cnt = PMN0; cnt <= CCNT; cnt++)
148 armv6_pmnc_reset_counter(cnt);
153 static void gator_events_armv6_stop(void)
157 for (cnt = PMN0; cnt <= CCNT; cnt++) {
158 pmnc_enabled[cnt] = 0;
163 static int gator_events_armv6_read(int **buffer, bool sched_switch)
166 int cpu = smp_processor_id();
168 /* a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled */
169 if (!(armv6_pmnc_read() & PMCR_E))
172 for (cnt = PMN0; cnt <= CCNT; cnt++) {
173 if (pmnc_enabled[cnt]) {
178 asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r" (value));
181 asm volatile("mrc p15, 0, %0, c15, c12, 2" : "=r" (value));
184 asm volatile("mrc p15, 0, %0, c15, c12, 3" : "=r" (value));
187 armv6_pmnc_reset_counter(cnt);
189 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
190 per_cpu(perfCnt, cpu)[len++] = value;
195 *buffer = per_cpu(perfCnt, cpu);
200 static struct gator_interface gator_events_armv6_interface = {
201 .create_files = gator_events_armv6_create_files,
202 .stop = gator_events_armv6_stop,
203 .online = gator_events_armv6_online,
204 .offline = gator_events_armv6_offline,
205 .read = gator_events_armv6_read,
208 int gator_events_armv6_init(void)
212 switch (gator_cpuid()) {
219 pmnc_name = "ARM11MPCore";
225 for (cnt = PMN0; cnt <= CCNT; cnt++) {
226 pmnc_enabled[cnt] = 0;
228 pmnc_key[cnt] = gator_events_get_key();
231 return gator_events_install(&gator_events_armv6_interface);