]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/arm-ds5-gator.git/blob - driver/gator_events_perf_pmu.c
gator-driver: Hack makefile to search for Mali trace headers
[android-sdk/arm-ds5-gator.git] / driver / gator_events_perf_pmu.c
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 <linux/slab.h>
10 #include <linux/perf_event.h>
11 #include "gator.h"
13 // gator_events_armvX.c is used for Linux 2.6.x
14 #if GATOR_PERF_PMU_SUPPORT
16 static const char *pmnc_name;
17 int pmnc_counters;
18 int ccnt = 0;
20 #define CNTMAX (6+1)
22 unsigned long pmnc_enabled[CNTMAX];
23 unsigned long pmnc_event[CNTMAX];
24 unsigned long pmnc_count[CNTMAX];
25 unsigned long pmnc_key[CNTMAX];
27 static DEFINE_PER_CPU(int[CNTMAX], perfCurr);
28 static DEFINE_PER_CPU(int[CNTMAX], perfPrev);
29 static DEFINE_PER_CPU(int[CNTMAX], perfPrevDelta);
30 static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
31 static DEFINE_PER_CPU(struct perf_event *[CNTMAX], pevent);
32 static DEFINE_PER_CPU(struct perf_event_attr *[CNTMAX], pevent_attr);
34 static void gator_events_perf_pmu_stop(void);
36 static int gator_events_perf_pmu_create_files(struct super_block *sb, struct dentry *root)
37 {
38         struct dentry *dir;
39         int i;
41         for (i = 0; i < pmnc_counters; i++) {
42                 char buf[40];
43                 if (i == 0) {
44                         snprintf(buf, sizeof buf, "%s_ccnt", pmnc_name);
45                 } else {
46                         snprintf(buf, sizeof buf, "%s_cnt%d", pmnc_name, i-1);
47                 }
48                 dir = gatorfs_mkdir(sb, root, buf);
49                 if (!dir) {
50                         return -1;
51                 }
52                 gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
53                 gatorfs_create_ulong(sb, dir, "count", &pmnc_count[i]);
54                 gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
55                 if (i > 0) {
56                         gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
57                 }
58         }
60         return 0;
61 }
63 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
64 static void dummy_handler(struct perf_event *event, int unused, struct perf_sample_data *data, struct pt_regs *regs)
65 #else
66 static void dummy_handler(struct perf_event *event, struct perf_sample_data *data, struct pt_regs *regs)
67 #endif
68 {
69 // Required as perf_event_create_kernel_counter() requires an overflow handler, even though all we do is poll
70 }
72 static int gator_events_perf_pmu_online(int** buffer)
73 {
74         int cnt, len = 0, cpu = smp_processor_id();
76         // read the counters and toss the invalid data, return zero instead
77         for (cnt = 0; cnt < pmnc_counters; cnt++) {
78                 struct perf_event * ev = per_cpu(pevent, cpu)[cnt];
79                 if (ev != NULL && ev->state == PERF_EVENT_STATE_ACTIVE) {
80                         ev->pmu->read(ev);
81                         per_cpu(perfPrev, cpu)[cnt] = per_cpu(perfCurr, cpu)[cnt] = local64_read(&ev->count);
82                         per_cpu(perfPrevDelta, cpu)[cnt] = 0;
83                         per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
84                         per_cpu(perfCnt, cpu)[len++] = 0;
85                 }
86         }
88         if (buffer)
89                 *buffer = per_cpu(perfCnt, cpu);
91         return len;
92 }
94 static void gator_events_perf_pmu_online_dispatch(int cpu)
95 {
96         int cnt;
98         for (cnt = 0; cnt < pmnc_counters; cnt++) {
99                 if (per_cpu(pevent, cpu)[cnt] != NULL || per_cpu(pevent_attr, cpu)[cnt] == 0)
100                         continue;
102 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
103                 per_cpu(pevent, cpu)[cnt] = perf_event_create_kernel_counter(per_cpu(pevent_attr, cpu)[cnt], cpu, 0, dummy_handler);
104 #else
105                 per_cpu(pevent, cpu)[cnt] = perf_event_create_kernel_counter(per_cpu(pevent_attr, cpu)[cnt], cpu, 0, dummy_handler, 0);
106 #endif
107                 if (IS_ERR(per_cpu(pevent, cpu)[cnt])) {
108                         pr_debug("gator: unable to online a counter on cpu %d\n", cpu);
109                         per_cpu(pevent, cpu)[cnt] = NULL;
110                         continue;
111                 }
113                 if (per_cpu(pevent, cpu)[cnt]->state != PERF_EVENT_STATE_ACTIVE) {
114                         pr_debug("gator: inactive counter on cpu %d\n", cpu);
115                         perf_event_release_kernel(per_cpu(pevent, cpu)[cnt]);
116                         per_cpu(pevent, cpu)[cnt] = NULL;
117                         continue;
118                 }
119         }
122 static void gator_events_perf_pmu_offline_dispatch(int cpu)
124         int cnt;
126         for (cnt = 0; cnt < pmnc_counters; cnt++) {
127                 if (per_cpu(pevent, cpu)[cnt] != NULL) {
128                         perf_event_release_kernel(per_cpu(pevent, cpu)[cnt]);
129                         per_cpu(pevent, cpu)[cnt] = NULL;
130                 }
131         }
134 static int gator_events_perf_pmu_start(void)
136         int cnt, cpu;
137         u32 size = sizeof(struct perf_event_attr);
139         for_each_present_cpu(cpu) {
140                 for (cnt = 0; cnt < pmnc_counters; cnt++) {
141                         per_cpu(pevent, cpu)[cnt] = NULL;
142                         if (!pmnc_enabled[cnt] || pmnc_count[cnt] > 0) // Skip disabled counters and EBS counters
143                                 continue;
145                         per_cpu(perfPrev, cpu)[cnt] = 0;
146                         per_cpu(perfCurr, cpu)[cnt] = 0;
147                         per_cpu(perfPrevDelta, cpu)[cnt] = 0;
148                         per_cpu(pevent_attr, cpu)[cnt] = kmalloc(size, GFP_KERNEL);
149                         if (!per_cpu(pevent_attr, cpu)[cnt]) {
150                                 gator_events_perf_pmu_stop();
151                                 return -1;
152                         }
154                         memset(per_cpu(pevent_attr, cpu)[cnt], 0, size);
155                         per_cpu(pevent_attr, cpu)[cnt]->type = PERF_TYPE_RAW;
156                         per_cpu(pevent_attr, cpu)[cnt]->size = size;
157                         per_cpu(pevent_attr, cpu)[cnt]->config = pmnc_event[cnt];
158                         per_cpu(pevent_attr, cpu)[cnt]->sample_period = 0;
159                         per_cpu(pevent_attr, cpu)[cnt]->pinned = 1;
161                         // handle special case for ccnt
162                         if (cnt == ccnt) {
163                                 per_cpu(pevent_attr, cpu)[cnt]->type = PERF_TYPE_HARDWARE;
164                                 per_cpu(pevent_attr, cpu)[cnt]->config = PERF_COUNT_HW_CPU_CYCLES;
165                         }
166                 }
167         }
169         return 0;
172 static void gator_events_perf_pmu_stop(void)
174         unsigned int cnt, cpu;
176         for_each_present_cpu(cpu) {
177                 for (cnt = 0; cnt < pmnc_counters; cnt++) {
178                         if (per_cpu(pevent_attr, cpu)[cnt]) {
179                                 kfree(per_cpu(pevent_attr, cpu)[cnt]);
180                                 per_cpu(pevent_attr, cpu)[cnt] = NULL;
181                         }
182                 }
183         }
185         for (cnt = 0; cnt < pmnc_counters; cnt++) {
186                 pmnc_enabled[cnt] = 0;
187                 pmnc_event[cnt] = 0;
188                 pmnc_count[cnt] = 0;
189         }
192 static int gator_events_perf_pmu_read(int **buffer)
194         int cnt, delta, len = 0;
195         int cpu = smp_processor_id();
197         for (cnt = 0; cnt < pmnc_counters; cnt++) {
198                 struct perf_event * ev = per_cpu(pevent, cpu)[cnt];
199                 if (ev != NULL && ev->state == PERF_EVENT_STATE_ACTIVE) {
200                         ev->pmu->read(ev);
201                         per_cpu(perfCurr, cpu)[cnt] = local64_read(&ev->count);
202                         delta = per_cpu(perfCurr, cpu)[cnt] - per_cpu(perfPrev, cpu)[cnt];
203                         if (delta != per_cpu(perfPrevDelta, cpu)[cnt]) {
204                                 per_cpu(perfPrevDelta, cpu)[cnt] = delta;
205                                 per_cpu(perfPrev, cpu)[cnt] = per_cpu(perfCurr, cpu)[cnt];
206                                 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
207                                 if (delta < 0)
208                                         delta *= -1;
209                                 per_cpu(perfCnt, cpu)[len++] = delta;
210                         }
211                 }
212         }
214         if (buffer)
215                 *buffer = per_cpu(perfCnt, cpu);
217         return len;
220 static struct gator_interface gator_events_perf_pmu_interface = {
221         .create_files = gator_events_perf_pmu_create_files,
222         .start = gator_events_perf_pmu_start,
223         .stop = gator_events_perf_pmu_stop,
224         .online = gator_events_perf_pmu_online,
225         .online_dispatch = gator_events_perf_pmu_online_dispatch,
226         .offline_dispatch = gator_events_perf_pmu_offline_dispatch,
227         .read = gator_events_perf_pmu_read,
228 };
230 int gator_events_perf_pmu_init(void)
232         unsigned int cnt;
234         switch (gator_cpuid()) {
235         case ARM1136:
236         case ARM1156:
237         case ARM1176:
238                 pmnc_name = "ARM_ARM11";
239                 pmnc_counters = 3;
240                 ccnt = 2;
241                 break;
242         case ARM11MPCORE:
243                 pmnc_name = "ARM_ARM11MPCore";
244                 pmnc_counters = 3;
245                 break;
246         case CORTEX_A5:
247                 pmnc_name = "ARM_Cortex-A5";
248                 pmnc_counters = 2;
249                 break;
250         case CORTEX_A7:
251                 pmnc_name = "ARM_Cortex-A7";
252                 pmnc_counters = 4;
253                 break;
254         case CORTEX_A8:
255                 pmnc_name = "ARM_Cortex-A8";
256                 pmnc_counters = 4;
257                 break;
258         case CORTEX_A9:
259                 pmnc_name = "ARM_Cortex-A9";
260                 pmnc_counters = 6;
261                 break;
262         case CORTEX_A15:
263                 pmnc_name = "ARM_Cortex-A15";
264                 pmnc_counters = 6;
265                 break;
266         case SCORPION:
267                 pmnc_name = "Scorpion";
268                 pmnc_counters = 4;
269                 break;
270         case SCORPIONMP:
271                 pmnc_name = "ScorpionMP";
272                 pmnc_counters = 4;
273                 break;
274         case KRAITSIM:
275         case KRAIT:
276                 pmnc_name = "Krait";
277                 pmnc_counters = 4;
278                 break;
279         default:
280                 return -1;
281         }
283         pmnc_counters++; // CNT[n] + CCNT
285         for (cnt = 0; cnt < CNTMAX; cnt++) {
286                 pmnc_enabled[cnt] = 0;
287                 pmnc_event[cnt] = 0;
288                 pmnc_count[cnt] = 0;
289                 pmnc_key[cnt] = gator_events_get_key();
290         }
292         return gator_events_install(&gator_events_perf_pmu_interface);
295 gator_events_init(gator_events_perf_pmu_init);
296 #endif