1 /**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved.
3 *
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.
7 */
9 #include "gator.h"
11 // gator_events_perf_pmu.c is used if perf is supported
12 #if GATOR_NO_PERF_SUPPORT
14 static const char *pmnc_name;
16 /*
17 * Per-CPU PMCR
18 */
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 */
26 #define PMN0 0
27 #define PMN1 1
28 #define CCNT 2
29 #define CNTMAX (CCNT+1)
31 static int pmnc_counters = 0;
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], perfPrev);
37 static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
39 static inline void armv6_pmnc_write(u32 val)
40 {
41 /* upper 4bits and 7, 11 are write-as-0 */
42 val &= 0x0ffff77f;
43 asm volatile("mcr p15, 0, %0, c15, c12, 0" : : "r" (val));
44 }
46 static inline u32 armv6_pmnc_read(void)
47 {
48 u32 val;
49 asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (val));
50 return val;
51 }
53 static void armv6_pmnc_reset_counter(unsigned int cnt)
54 {
55 u32 val = 0;
56 switch (cnt) {
57 case CCNT:
58 asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r" (val));
59 break;
60 case PMN0:
61 asm volatile("mcr p15, 0, %0, c15, c12, 2" : : "r" (val));
62 break;
63 case PMN1:
64 asm volatile("mcr p15, 0, %0, c15, c12, 3" : : "r" (val));
65 break;
66 }
67 }
69 int gator_events_armv6_create_files(struct super_block *sb, struct dentry *root)
70 {
71 struct dentry *dir;
72 int i;
74 pmnc_counters = 3;
76 for (i = PMN0; i <= CCNT; i++) {
77 char buf[40];
78 if (i == CCNT) {
79 snprintf(buf, sizeof buf, "ARM_%s_ccnt", pmnc_name);
80 } else {
81 snprintf(buf, sizeof buf, "ARM_%s_cnt%d", pmnc_name, i);
82 }
83 dir = gatorfs_mkdir(sb, root, buf);
84 if (!dir) {
85 return -1;
86 }
87 gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
88 gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
89 if (i != CCNT) {
90 gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
91 }
92 }
94 return 0;
95 }
97 static int gator_events_armv6_online(int** buffer)
98 {
99 unsigned int cnt, len = 0, cpu = smp_processor_id();
100 u32 pmnc;
102 if (armv6_pmnc_read() & PMCR_E) {
103 armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
104 }
106 /* initialize PMNC, reset overflow, D bit, C bit and P bit. */
107 armv6_pmnc_write(PMCR_OFL_PMN0 | PMCR_OFL_PMN1 | PMCR_OFL_CCNT |
108 PMCR_C | PMCR_P);
110 /* configure control register */
111 for (pmnc = 0, cnt = PMN0; cnt <= CCNT; cnt++) {
112 unsigned long event;
114 per_cpu(perfPrev, cpu)[cnt] = 0;
116 if (!pmnc_enabled[cnt])
117 continue;
119 event = pmnc_event[cnt] & 255;
121 // Set event (if destined for PMNx counters)
122 if (cnt == PMN0) {
123 pmnc |= event << 20;
124 } else if (cnt == PMN1) {
125 pmnc |= event << 12;
126 }
128 // Reset counter
129 armv6_pmnc_reset_counter(cnt);
130 }
131 armv6_pmnc_write(pmnc | PMCR_E);
133 // return zero values, no need to read as the counters were just reset
134 for (cnt = PMN0; cnt <= CCNT; cnt++) {
135 if (pmnc_enabled[cnt]) {
136 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
137 per_cpu(perfCnt, cpu)[len++] = 0;
138 }
139 }
141 if (buffer)
142 *buffer = per_cpu(perfCnt, cpu);
144 return len;
145 }
147 static int gator_events_armv6_offline(int** buffer)
148 {
149 unsigned int cnt;
151 armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
152 for (cnt = PMN0; cnt <= CCNT; cnt++) {
153 armv6_pmnc_reset_counter(cnt);
154 }
156 return 0;
157 }
159 static void gator_events_armv6_stop(void)
160 {
161 unsigned int cnt;
163 for (cnt = PMN0; cnt <= CCNT; cnt++) {
164 pmnc_enabled[cnt] = 0;
165 pmnc_event[cnt] = 0;
166 }
167 }
169 static int gator_events_armv6_read(int **buffer)
170 {
171 int cnt, len = 0;
172 int cpu = smp_processor_id();
174 for (cnt = PMN0; cnt <= CCNT; cnt++) {
175 if (pmnc_enabled[cnt]) {
176 u32 value = 0;
177 switch (cnt) {
178 case CCNT:
179 asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r" (value));
180 break;
181 case PMN0:
182 asm volatile("mrc p15, 0, %0, c15, c12, 2" : "=r" (value));
183 break;
184 case PMN1:
185 asm volatile("mrc p15, 0, %0, c15, c12, 3" : "=r" (value));
186 break;
187 }
188 armv6_pmnc_reset_counter(cnt);
189 if (value != per_cpu(perfPrev, cpu)[cnt]) {
190 per_cpu(perfPrev, cpu)[cnt] = value;
191 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
192 per_cpu(perfCnt, cpu)[len++] = value;
193 }
194 }
195 }
197 if (buffer)
198 *buffer = per_cpu(perfCnt, cpu);
200 return len;
201 }
203 static struct gator_interface gator_events_armv6_interface = {
204 .create_files = gator_events_armv6_create_files,
205 .stop = gator_events_armv6_stop,
206 .online = gator_events_armv6_online,
207 .offline = gator_events_armv6_offline,
208 .read = gator_events_armv6_read,
209 };
211 int gator_events_armv6_init(void)
212 {
213 unsigned int cnt;
215 switch (gator_cpuid()) {
216 case ARM1136:
217 case ARM1156:
218 case ARM1176:
219 pmnc_name = "ARM11";
220 break;
221 case ARM11MPCORE:
222 pmnc_name = "ARM11MPCore";
223 break;
224 default:
225 return -1;
226 }
228 for (cnt = PMN0; cnt <= CCNT; cnt++) {
229 pmnc_enabled[cnt] = 0;
230 pmnc_event[cnt] = 0;
231 pmnc_key[cnt] = gator_events_get_key();
232 }
234 return gator_events_install(&gator_events_armv6_interface);
235 }
237 gator_events_init(gator_events_armv6_init);
239 #else
240 int gator_events_armv6_init(void)
241 {
242 return -1;
243 }
244 #endif