]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/arm-ds5-gator.git/blob - driver/gator_events_armv6.c
gator-driver: Handle task struct correctly
[android-sdk/arm-ds5-gator.git] / driver / gator_events_armv6.c
1 /**
2  * Copyright (C) ARM Limited 2010-2013. 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 * 2], perfCnt);
38 static inline void armv6_pmnc_write(u32 val)
39 {
40         /* upper 4bits and 7, 11 are write-as-0 */
41         val &= 0x0ffff77f;
42         asm volatile("mcr p15, 0, %0, c15, c12, 0" : : "r" (val));
43 }
45 static inline u32 armv6_pmnc_read(void)
46 {
47         u32 val;
48         asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (val));
49         return val;
50 }
52 static void armv6_pmnc_reset_counter(unsigned int cnt)
53 {
54         u32 val = 0;
55         switch (cnt) {
56         case CCNT:
57                 asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r" (val));
58                 break;
59         case PMN0:
60                 asm volatile("mcr p15, 0, %0, c15, c12, 2" : : "r" (val));
61                 break;
62         case PMN1:
63                 asm volatile("mcr p15, 0, %0, c15, c12, 3" : : "r" (val));
64                 break;
65         }
66 }
68 int gator_events_armv6_create_files(struct super_block *sb, struct dentry *root)
69 {
70         struct dentry *dir;
71         int i;
73         pmnc_counters = 3;
75         for (i = PMN0; i <= CCNT; i++) {
76                 char buf[40];
77                 if (i == CCNT) {
78                         snprintf(buf, sizeof buf, "ARM_%s_ccnt", pmnc_name);
79                 } else {
80                         snprintf(buf, sizeof buf, "ARM_%s_cnt%d", pmnc_name, i);
81                 }
82                 dir = gatorfs_mkdir(sb, root, buf);
83                 if (!dir) {
84                         return -1;
85                 }
86                 gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
87                 gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
88                 if (i != CCNT) {
89                         gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
90                 }
91         }
93         return 0;
94 }
96 static int gator_events_armv6_online(int **buffer, bool migrate)
97 {
98         unsigned int cnt, len = 0, cpu = smp_processor_id();
99         u32 pmnc;
101         if (armv6_pmnc_read() & PMCR_E) {
102                 armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
103         }
105         /* initialize PMNC, reset overflow, D bit, C bit and P bit. */
106         armv6_pmnc_write(PMCR_OFL_PMN0 | PMCR_OFL_PMN1 | PMCR_OFL_CCNT |
107                          PMCR_C | PMCR_P);
109         /* configure control register */
110         for (pmnc = 0, cnt = PMN0; cnt <= CCNT; cnt++) {
111                 unsigned long event;
113                 if (!pmnc_enabled[cnt])
114                         continue;
116                 event = pmnc_event[cnt] & 255;
118                 // Set event (if destined for PMNx counters)
119                 if (cnt == PMN0) {
120                         pmnc |= event << 20;
121                 } else if (cnt == PMN1) {
122                         pmnc |= event << 12;
123                 }
125                 // Reset counter
126                 armv6_pmnc_reset_counter(cnt);
127         }
128         armv6_pmnc_write(pmnc | PMCR_E);
130         // return zero values, no need to read as the counters were just reset
131         for (cnt = PMN0; cnt <= CCNT; cnt++) {
132                 if (pmnc_enabled[cnt]) {
133                         per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
134                         per_cpu(perfCnt, cpu)[len++] = 0;
135                 }
136         }
138         if (buffer)
139                 *buffer = per_cpu(perfCnt, cpu);
141         return len;
144 static int gator_events_armv6_offline(int **buffer, bool migrate)
146         unsigned int cnt;
148         armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
149         for (cnt = PMN0; cnt <= CCNT; cnt++) {
150                 armv6_pmnc_reset_counter(cnt);
151         }
153         return 0;
156 static void gator_events_armv6_stop(void)
158         unsigned int cnt;
160         for (cnt = PMN0; cnt <= CCNT; cnt++) {
161                 pmnc_enabled[cnt] = 0;
162                 pmnc_event[cnt] = 0;
163         }
166 static int gator_events_armv6_read(int **buffer)
168         int cnt, len = 0;
169         int cpu = smp_processor_id();
171         // a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled
172         if (!(armv6_pmnc_read() & PMCR_E)) {
173                 return 0;
174         }
176         for (cnt = PMN0; cnt <= CCNT; cnt++) {
177                 if (pmnc_enabled[cnt]) {
178                         u32 value = 0;
179                         switch (cnt) {
180                         case CCNT:
181                                 asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r" (value));
182                                 break;
183                         case PMN0:
184                                 asm volatile("mrc p15, 0, %0, c15, c12, 2" : "=r" (value));
185                                 break;
186                         case PMN1:
187                                 asm volatile("mrc p15, 0, %0, c15, c12, 3" : "=r" (value));
188                                 break;
189                         }
190                         armv6_pmnc_reset_counter(cnt);
192                         per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
193                         per_cpu(perfCnt, cpu)[len++] = value;
194                 }
195         }
197         if (buffer)
198                 *buffer = per_cpu(perfCnt, cpu);
200         return len;
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)
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);
237 #endif