Merge branch 'linux-3.10.y' of git://git.kernel.org/pub/scm/linux/kernel/git/stable...
[firefly-linux-kernel-4.4.55.git] / drivers / gator / gator_events_armv6.c
1 /**
2  * Copyright (C) ARM Limited 2010-2015. 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  */
8
9 #include "gator.h"
10
11 /* gator_events_perf_pmu.c is used if perf is supported */
12 #if GATOR_NO_PERF_SUPPORT
13
14 static const char *pmnc_name;
15
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 */
25
26 #define PMN0 0
27 #define PMN1 1
28 #define CCNT 2
29 #define CNTMAX  (CCNT+1)
30
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];
35
36 static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
37
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 }
44
45 static inline u32 armv6_pmnc_read(void)
46 {
47         u32 val;
48
49         asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (val));
50         return val;
51 }
52
53 static void armv6_pmnc_reset_counter(unsigned int cnt)
54 {
55         u32 val = 0;
56
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 }
69
70 int gator_events_armv6_create_files(struct super_block *sb, struct dentry *root)
71 {
72         struct dentry *dir;
73         int i;
74
75         pmnc_counters = 3;
76
77         for (i = PMN0; i <= CCNT; i++) {
78                 char buf[40];
79
80                 if (i == CCNT)
81                         snprintf(buf, sizeof(buf), "ARM_%s_ccnt", pmnc_name);
82                 else
83                         snprintf(buf, sizeof(buf), "ARM_%s_cnt%d", pmnc_name, i);
84                 dir = gatorfs_mkdir(sb, root, buf);
85                 if (!dir)
86                         return -1;
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
93         return 0;
94 }
95
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;
100
101         if (armv6_pmnc_read() & PMCR_E)
102                 armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
103
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 |
106                          PMCR_C | PMCR_P);
107
108         /* configure control register */
109         for (pmnc = 0, cnt = PMN0; cnt <= CCNT; cnt++) {
110                 unsigned long event;
111
112                 if (!pmnc_enabled[cnt])
113                         continue;
114
115                 event = pmnc_event[cnt] & 255;
116
117                 /* Set event (if destined for PMNx counters) */
118                 if (cnt == PMN0)
119                         pmnc |= event << 20;
120                 else if (cnt == PMN1)
121                         pmnc |= event << 12;
122
123                 /* Reset counter */
124                 armv6_pmnc_reset_counter(cnt);
125         }
126         armv6_pmnc_write(pmnc | PMCR_E);
127
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;
133                 }
134         }
135
136         if (buffer)
137                 *buffer = per_cpu(perfCnt, cpu);
138
139         return len;
140 }
141
142 static int gator_events_armv6_offline(int **buffer, bool migrate)
143 {
144         unsigned int cnt;
145
146         armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
147         for (cnt = PMN0; cnt <= CCNT; cnt++)
148                 armv6_pmnc_reset_counter(cnt);
149
150         return 0;
151 }
152
153 static void gator_events_armv6_stop(void)
154 {
155         unsigned int cnt;
156
157         for (cnt = PMN0; cnt <= CCNT; cnt++) {
158                 pmnc_enabled[cnt] = 0;
159                 pmnc_event[cnt] = 0;
160         }
161 }
162
163 static int gator_events_armv6_read(int **buffer, bool sched_switch)
164 {
165         int cnt, len = 0;
166         int cpu = smp_processor_id();
167
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))
170                 return 0;
171
172         for (cnt = PMN0; cnt <= CCNT; cnt++) {
173                 if (pmnc_enabled[cnt]) {
174                         u32 value = 0;
175
176                         switch (cnt) {
177                         case CCNT:
178                                 asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r" (value));
179                                 break;
180                         case PMN0:
181                                 asm volatile("mrc p15, 0, %0, c15, c12, 2" : "=r" (value));
182                                 break;
183                         case PMN1:
184                                 asm volatile("mrc p15, 0, %0, c15, c12, 3" : "=r" (value));
185                                 break;
186                         }
187                         armv6_pmnc_reset_counter(cnt);
188
189                         per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
190                         per_cpu(perfCnt, cpu)[len++] = value;
191                 }
192         }
193
194         if (buffer)
195                 *buffer = per_cpu(perfCnt, cpu);
196
197         return len;
198 }
199
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,
206 };
207
208 int gator_events_armv6_init(void)
209 {
210         unsigned int cnt;
211
212         switch (gator_cpuid()) {
213         case ARM1136:
214         case ARM1156:
215         case ARM1176:
216                 pmnc_name = "ARM11";
217                 break;
218         case ARM11MPCORE:
219                 pmnc_name = "ARM11MPCore";
220                 break;
221         default:
222                 return -1;
223         }
224
225         for (cnt = PMN0; cnt <= CCNT; cnt++) {
226                 pmnc_enabled[cnt] = 0;
227                 pmnc_event[cnt] = 0;
228                 pmnc_key[cnt] = gator_events_get_key();
229         }
230
231         return gator_events_install(&gator_events_armv6_interface);
232 }
233
234 #endif