7b1d875084f744fb8ed72f034e4c412969556fd9
[android-sdk/arm-ds5-gator.git] / gator_events_armv6.c
1 /**
2  * Copyright (C) ARM Limited 2010-2011. 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 #define ARM1136         0xb36
12 #define ARM1156         0xb56
13 #define ARM1176         0xb76
15 static const char *pmnc_name;
17 /*
18  * Per-CPU PMCR
19  */
20 #define PMCR_E                  (1 << 0)        /* Enable */
21 #define PMCR_P                  (1 << 1)        /* Count reset */
22 #define PMCR_C                  (1 << 2)        /* Cycle counter reset */
23 #define PMCR_OFL_PMN0   (1 << 8)        /* Count reg 0 overflow */
24 #define PMCR_OFL_PMN1   (1 << 9)        /* Count reg 1 overflow */
25 #define PMCR_OFL_CCNT   (1 << 10)       /* Cycle counter overflow */
27 #define PMN0 0
28 #define PMN1 1
29 #define CCNT 2
30 #define CNTMAX  (CCNT+1)
32 static int pmnc_count = 0;
33 static unsigned long pmnc_enabled[CNTMAX];
34 static unsigned long pmnc_event[CNTMAX];
35 static unsigned long pmnc_key[CNTMAX];
37 static DEFINE_PER_CPU(int[CNTMAX], perfPrev);
38 static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
40 static inline void armv6_pmnc_write(u32 val)
41 {
42         /* upper 4bits and 7, 11 are write-as-0 */
43         val &= 0x0ffff77f;
44         asm volatile("mcr p15, 0, %0, c15, c12, 0" : : "r" (val));
45 }
47 static inline u32 armv6_pmnc_read(void)
48 {
49         u32 val;
50         asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (val));
51         return val;
52 }
54 static void armv6_pmnc_reset_counter(unsigned int cnt)
55 {
56         u32 val = 0;
57         switch (cnt) {
58         case CCNT:
59                 asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r" (val));
60                 break;
61         case PMN0:
62                 asm volatile("mcr p15, 0, %0, c15, c12, 2" : : "r" (val));
63                 break;
64         case PMN1:
65                 asm volatile("mcr p15, 0, %0, c15, c12, 3" : : "r" (val));
66                 break;
67         }
68 }
70 int gator_events_armv6_create_files(struct super_block *sb, struct dentry *root)
71 {
72         struct dentry *dir;
73         int i;
75         pmnc_count = 3;
77         for (i = PMN0; i <= CCNT; i++) {
78                 char buf[40];
79                 if (i == CCNT) {
80                         snprintf(buf, sizeof buf, "ARM_%s_ccnt", pmnc_name);
81                 } else {
82                         snprintf(buf, sizeof buf, "ARM_%s_cnt%d", pmnc_name, i);
83                 }
84                 dir = gatorfs_mkdir(sb, root, buf);
85                 if (!dir) {
86                         return -1;
87                 }
88                 gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
89                 if (i != CCNT) {
90                         gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
91                 }
92                 gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
93         }
95         return 0;
96 }
98 static void gator_events_armv6_online(void)
99 {
100         unsigned int cnt;
101         u32 pmnc;
103         if (armv6_pmnc_read() & PMCR_E) {
104                 armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
105         }
107         /* initialize PMNC, reset overflow, D bit, C bit and P bit. */
108         armv6_pmnc_write(PMCR_OFL_PMN0 | PMCR_OFL_PMN1 | PMCR_OFL_CCNT |
109                         PMCR_C | PMCR_P);
111         /* configure control register */
112         for (pmnc = 0, cnt = PMN0; cnt <= CCNT; cnt++) {
113                 unsigned long event;
115                 per_cpu(perfPrev, smp_processor_id())[cnt] = 0;
117                 if (!pmnc_enabled[cnt])
118                         continue;
120                 event = pmnc_event[cnt] & 255;
122                 /*
123                  * Set event (if destined for PMNx counters)
124                  */
125                 if (cnt == PMN0) {
126                         pmnc |= event << 20;
127                 } else if (cnt == PMN1) {
128                         pmnc |= event << 12;
129                 }
131                 /*
132                  * Reset counter
133                  */
134                 armv6_pmnc_reset_counter(cnt);
135         }
136         armv6_pmnc_write(pmnc | PMCR_E);
139 static void gator_events_armv6_offline(void)
141         unsigned int cnt;
143         armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
144         for (cnt = PMN0; cnt <= CCNT; cnt++) {
145                 armv6_pmnc_reset_counter(cnt);
146         }
149 static void gator_events_armv6_stop(void)
151         unsigned int cnt;
153         for (cnt = PMN0; cnt <= CCNT; cnt++) {
154                 pmnc_enabled[cnt] = 0;
155                 pmnc_event[cnt] = 0;
156         }
159 static int gator_events_armv6_read(int **buffer)
161         int cnt, len = 0;
162         int cpu = smp_processor_id();
164         for (cnt = PMN0; cnt <= CCNT; cnt++) {
165                 if (pmnc_enabled[cnt]) {
166                         u32 value = 0;
167                         switch (cnt) {
168                         case CCNT:
169                                 asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r" (value));
170                                 break;
171                         case PMN0:
172                                 asm volatile("mrc p15, 0, %0, c15, c12, 2" : "=r" (value));
173                                 break;
174                         case PMN1:
175                                 asm volatile("mrc p15, 0, %0, c15, c12, 3" : "=r" (value));
176                                 break;
177                         }
178                         armv6_pmnc_reset_counter(cnt);
179                         if (value != per_cpu(perfPrev, cpu)[cnt]) {
180                                 per_cpu(perfPrev, cpu)[cnt] = value;
181                                 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
182                                 per_cpu(perfCnt, cpu)[len++] = value;
183                         }
184                 }
185         }
187         // update or discard
188         if (buffer)
189                 *buffer = per_cpu(perfCnt, cpu);
191         return len;
194 static struct gator_interface gator_events_armv6_interface = {
195         .create_files = gator_events_armv6_create_files,
196         .stop = gator_events_armv6_stop,
197         .online = gator_events_armv6_online,
198         .offline = gator_events_armv6_offline,
199         .read = gator_events_armv6_read,
200 };
202 int gator_events_armv6_init(void)
204         unsigned int cnt;
206         switch (gator_cpuid()) {
207         case ARM1136:
208         case ARM1156:
209         case ARM1176:
210                 pmnc_name = "ARM11";
211                 break;
212         default:
213                 return -1;
214         }
216         for (cnt = PMN0; cnt <= CCNT; cnt++) {
217                 pmnc_enabled[cnt] = 0;
218                 pmnc_event[cnt] = 0;
219                 pmnc_key[cnt] = gator_events_get_key();
220         }
222         return gator_events_install(&gator_events_armv6_interface);
224 gator_events_init(gator_events_armv6_init);