ARM: tegra: Add Tegra Profiler
[linux-2.6.git] / drivers / misc / tegra-profiler / main.c
1 /*
2  * drivers/misc/tegra-profiler/main.c
3  *
4  * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  */
16
17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18
19 #include <linux/init.h>
20 #include <linux/module.h>
21
22 #include <linux/tegra_profiler.h>
23
24 #include "quadd.h"
25 #include "armv7_pmu.h"
26 #include "hrt.h"
27 #include "pl310.h"
28 #include "comm.h"
29 #include "mmap.h"
30 #include "debug.h"
31 #include "tegra.h"
32 #include "power_clk.h"
33 #include "auth.h"
34 #include "version.h"
35
36 static struct quadd_ctx ctx;
37
38 static int get_default_properties(void)
39 {
40         ctx.param.freq = 100;
41         ctx.param.ma_freq = 50;
42         ctx.param.backtrace = 1;
43         ctx.param.use_freq = 1;
44         ctx.param.system_wide = 1;
45         ctx.param.power_rate_freq = 0;
46         ctx.param.debug_samples = 0;
47
48         ctx.param.pids[0] = 0;
49         ctx.param.nr_pids = 1;
50
51         return 0;
52 }
53
54 static int start(void)
55 {
56         int err;
57
58         if (!atomic_cmpxchg(&ctx.started, 0, 1)) {
59                 if (ctx.pmu) {
60                         err = ctx.pmu->enable();
61                         if (err) {
62                                 pr_err("error: pmu enable\n");
63                                 return err;
64                         }
65                 }
66
67                 if (ctx.pl310) {
68                         err = ctx.pl310->enable();
69                         if (err) {
70                                 pr_err("error: pl310 enable\n");
71                                 return err;
72                         }
73                 }
74
75                 quadd_mmap_reset();
76                 ctx.comm->reset();
77
78                 err = quadd_power_clk_start();
79                 if (err < 0) {
80                         pr_err("error: power_clk start\n");
81                         return err;
82                 }
83
84                 err = quadd_hrt_start();
85                 if (err) {
86                         pr_err("error: hrt start\n");
87                         return err;
88                 }
89         }
90
91         return 0;
92 }
93
94 static void stop(void)
95 {
96         if (atomic_cmpxchg(&ctx.started, 1, 0)) {
97                 quadd_hrt_stop();
98
99                 quadd_mmap_reset();
100                 ctx.comm->reset();
101
102                 quadd_power_clk_stop();
103
104                 if (ctx.pmu)
105                         ctx.pmu->disable();
106
107                 if (ctx.pl310)
108                         ctx.pl310->disable();
109         }
110 }
111
112 static inline int is_event_supported(struct source_info *si, int event)
113 {
114         int i;
115         int nr = si->nr_supported_events;
116         int *events = si->supported_events;
117
118         for (i = 0; i < nr; i++) {
119                 if (event == events[i])
120                         return 1;
121         }
122         return 0;
123 }
124
125 static int set_parameters(struct quadd_parameters *param, uid_t *debug_app_uid)
126 {
127         int i, err;
128         int pmu_events_id[QUADD_MAX_COUNTERS];
129         int pl310_events_id;
130         int nr_pmu = 0, nr_pl310 = 0;
131         int uid = 0;
132         struct task_struct *task;
133
134         if (ctx.param.freq != 100 && ctx.param.freq != 1000 &&
135             ctx.param.freq != 10000)
136                 return -EINVAL;
137
138         ctx.param.freq = param->freq;
139         ctx.param.ma_freq = param->ma_freq;
140         ctx.param.backtrace = param->backtrace;
141         ctx.param.use_freq = param->use_freq;
142         ctx.param.system_wide = param->system_wide;
143         ctx.param.power_rate_freq = param->power_rate_freq;
144         ctx.param.debug_samples = param->debug_samples;
145
146         /* Currently only one process */
147         if (param->nr_pids != 1)
148                 return -EINVAL;
149
150         rcu_read_lock();
151         task = pid_task(find_vpid(param->pids[0]), PIDTYPE_PID);
152         rcu_read_unlock();
153         if (!task) {
154                 pr_err("Process not found: %u\n", param->pids[0]);
155                 return -ESRCH;
156         }
157
158         pr_info("owner/task uids: %u/%u\n", current_fsuid(), task_uid(task));
159         if (!capable(CAP_SYS_ADMIN)) {
160                 if (current_fsuid() != task_uid(task)) {
161                         uid = quadd_auth_check_debug_flag(param->package_name);
162                         if (uid < 0) {
163                                 pr_err("Error: QuadD security service\n");
164                                 return uid;
165                         } else if (uid == 0) {
166                                 pr_err("Error: app is not debuggable\n");
167                                 return -EACCES;
168                         }
169
170                         *debug_app_uid = uid;
171                         pr_info("debug_app_uid: %u\n", uid);
172                 }
173         }
174
175         for (i = 0; i < param->nr_pids; i++)
176                 ctx.param.pids[i] = param->pids[i];
177
178         ctx.param.nr_pids = param->nr_pids;
179
180         for (i = 0; i < param->nr_events; i++) {
181                 int event = param->events[i];
182
183                 if (ctx.pmu && ctx.pmu_info.nr_supported_events > 0
184                         && is_event_supported(&ctx.pmu_info, event)) {
185                         pmu_events_id[nr_pmu++] = param->events[i];
186
187                         pr_info("PMU active event: %s\n",
188                                 quadd_get_event_str(event));
189                 } else if (ctx.pl310 &&
190                            ctx.pl310_info.nr_supported_events > 0 &&
191                            is_event_supported(&ctx.pl310_info, event)) {
192                         pl310_events_id = param->events[i];
193
194                         pr_info("PL310 active event: %s\n",
195                                 quadd_get_event_str(event));
196
197                         if (nr_pl310++ > 1) {
198                                 pr_err("error: multiply pl310 events\n");
199                                 return -EINVAL;
200                         }
201                 } else {
202                         pr_err("Bad event: %s\n",
203                                quadd_get_event_str(event));
204                         return -EINVAL;
205                 }
206         }
207
208         if (ctx.pmu) {
209                 if (nr_pmu > 0) {
210                         err = ctx.pmu->set_events(pmu_events_id, nr_pmu);
211                         if (err) {
212                                 pr_err("PMU set parameters: error\n");
213                                 return err;
214                         }
215                         ctx.pmu_info.active = 1;
216                 } else {
217                         ctx.pmu_info.active = 0;
218                         ctx.pmu->set_events(NULL, 0);
219                 }
220         }
221
222         if (ctx.pl310) {
223                 if (nr_pl310 == 1) {
224                         err = ctx.pl310->set_events(&pl310_events_id, 1);
225                         if (err) {
226                                 pr_info("pl310 set_parameters: error\n");
227                                 return err;
228                         }
229                         ctx.pl310_info.active = 1;
230                 } else {
231                         ctx.pl310_info.active = 0;
232                         ctx.pl310->set_events(NULL, 0);
233                 }
234         }
235         pr_info("New parameters have been applied\n");
236
237         return 0;
238 }
239
240 static void get_capabilities(struct quadd_comm_cap *cap)
241 {
242         int i, event;
243         struct quadd_events_cap *events_cap = &cap->events_cap;
244
245         cap->pmu = ctx.pmu ? 1 : 0;
246
247         cap->l2_cache = 0;
248         if (ctx.pl310) {
249                 cap->l2_cache = 1;
250                 cap->l2_multiple_events = 0;
251         } else if (ctx.pmu) {
252                 struct source_info *s = &ctx.pmu_info;
253                 for (i = 0; i < s->nr_supported_events; i++) {
254                         event = s->supported_events[i];
255                         if (event == QUADD_EVENT_TYPE_L2_DCACHE_READ_MISSES ||
256                             event == QUADD_EVENT_TYPE_L2_DCACHE_WRITE_MISSES ||
257                             event == QUADD_EVENT_TYPE_L2_ICACHE_MISSES) {
258                                 cap->l2_cache = 1;
259                                 cap->l2_multiple_events = 1;
260                                 break;
261                         }
262                 }
263         }
264
265         events_cap->cpu_cycles = 0;
266         events_cap->l1_dcache_read_misses = 0;
267         events_cap->l1_dcache_write_misses = 0;
268         events_cap->l1_icache_misses = 0;
269
270         events_cap->instructions = 0;
271         events_cap->branch_instructions = 0;
272         events_cap->branch_misses = 0;
273         events_cap->bus_cycles = 0;
274
275         events_cap->l2_dcache_read_misses = 0;
276         events_cap->l2_dcache_write_misses = 0;
277         events_cap->l2_icache_misses = 0;
278
279         if (ctx.pl310) {
280                 struct source_info *s = &ctx.pl310_info;
281                 for (i = 0; i < s->nr_supported_events; i++) {
282                         int event = s->supported_events[i];
283
284                         switch (event) {
285                         case QUADD_EVENT_TYPE_L2_DCACHE_READ_MISSES:
286                                 events_cap->l2_dcache_read_misses = 1;
287                                 break;
288                         case QUADD_EVENT_TYPE_L2_DCACHE_WRITE_MISSES:
289                                 events_cap->l2_dcache_write_misses = 1;
290                                 break;
291                         case QUADD_EVENT_TYPE_L2_ICACHE_MISSES:
292                                 events_cap->l2_icache_misses = 1;
293                                 break;
294
295                         default:
296                                 BUG();
297                                 break;
298                         }
299                 }
300         }
301
302         if (ctx.pmu) {
303                 struct source_info *s = &ctx.pmu_info;
304                 for (i = 0; i < s->nr_supported_events; i++) {
305                         int event = s->supported_events[i];
306
307                         switch (event) {
308                         case QUADD_EVENT_TYPE_CPU_CYCLES:
309                                 events_cap->cpu_cycles = 1;
310                                 break;
311                         case QUADD_EVENT_TYPE_INSTRUCTIONS:
312                                 events_cap->instructions = 1;
313                                 break;
314                         case QUADD_EVENT_TYPE_BRANCH_INSTRUCTIONS:
315                                 events_cap->branch_instructions = 1;
316                                 break;
317                         case QUADD_EVENT_TYPE_BRANCH_MISSES:
318                                 events_cap->branch_misses = 1;
319                                 break;
320                         case QUADD_EVENT_TYPE_BUS_CYCLES:
321                                 events_cap->bus_cycles = 1;
322                                 break;
323
324                         case QUADD_EVENT_TYPE_L1_DCACHE_READ_MISSES:
325                                 events_cap->l1_dcache_read_misses = 1;
326                                 break;
327                         case QUADD_EVENT_TYPE_L1_DCACHE_WRITE_MISSES:
328                                 events_cap->l1_dcache_write_misses = 1;
329                                 break;
330                         case QUADD_EVENT_TYPE_L1_ICACHE_MISSES:
331                                 events_cap->l1_icache_misses = 1;
332                                 break;
333
334                         case QUADD_EVENT_TYPE_L2_DCACHE_READ_MISSES:
335                                 events_cap->l2_dcache_read_misses = 1;
336                                 break;
337                         case QUADD_EVENT_TYPE_L2_DCACHE_WRITE_MISSES:
338                                 events_cap->l2_dcache_write_misses = 1;
339                                 break;
340                         case QUADD_EVENT_TYPE_L2_ICACHE_MISSES:
341                                 events_cap->l2_icache_misses = 1;
342                                 break;
343
344                         default:
345                                 BUG();
346                                 break;
347                         }
348                 }
349         }
350
351         cap->tegra_lp_cluster = quadd_is_cpu_with_lp_cluster();
352         cap->power_rate = 1;
353         cap->blocked_read = 0;
354 }
355
356 static void get_state(struct quadd_module_state *state)
357 {
358         quadd_hrt_get_state(state);
359 }
360
361 static struct quadd_comm_control_interface control = {
362         .start                  = start,
363         .stop                   = stop,
364         .set_parameters         = set_parameters,
365         .get_capabilities       = get_capabilities,
366         .get_state              = get_state,
367 };
368
369 static int __init quadd_module_init(void)
370 {
371         int i, nr_events, err;
372         int *events;
373
374         pr_info("Branch: %s\n", QUADD_MODULE_BRANCH);
375         pr_info("Version: %s\n", QUADD_MODULE_VERSION);
376         pr_info("Samples version: %d\n", QUADD_SAMPLES_VERSION);
377         pr_info("IO version: %d\n", QUADD_IO_VERSION);
378
379 #ifdef QM_DEBUG_SAMPLES_ENABLE
380         pr_info("############## DEBUG VERSION! ##############\n");
381 #endif
382         atomic_set(&ctx.started, 0);
383
384         get_default_properties();
385
386         ctx.pmu_info.active = 0;
387         ctx.pl310_info.active = 0;
388
389         ctx.pmu = quadd_armv7_pmu_init();
390         if (!ctx.pmu) {
391                 pr_err("PMU init failed\n");
392                 return -ENODEV;
393         } else {
394                 events = ctx.pmu_info.supported_events;
395                 nr_events = ctx.pmu->get_supported_events(events);
396                 ctx.pmu_info.nr_supported_events = nr_events;
397
398                 pr_info("PMU: amount of events: %d\n", nr_events);
399
400                 for (i = 0; i < nr_events; i++)
401                         pr_info("PMU event: %s\n",
402                                 quadd_get_event_str(events[i]));
403         }
404
405         ctx.pl310 = quadd_l2x0_events_init();
406         if (ctx.pl310) {
407                 events = ctx.pl310_info.supported_events;
408                 nr_events = ctx.pl310->get_supported_events(events);
409                 ctx.pl310_info.nr_supported_events = nr_events;
410
411                 pr_info("pl310 success, amount of events: %d\n",
412                         nr_events);
413
414                 for (i = 0; i < nr_events; i++)
415                         pr_info("pl310 event: %s\n",
416                                 quadd_get_event_str(events[i]));
417         } else {
418                 pr_info("PL310 not found\n");
419         }
420
421         ctx.hrt = quadd_hrt_init(&ctx);
422         if (!ctx.hrt) {
423                 pr_err("error: HRT init failed\n");
424                 return -ENODEV;
425         }
426
427         ctx.mmap = quadd_mmap_init(&ctx);
428         if (!ctx.mmap) {
429                 pr_err("error: MMAP init failed\n");
430                 return -ENODEV;
431         }
432
433         err = quadd_power_clk_init(&ctx);
434         if (err < 0) {
435                 pr_err("error: POWER CLK init failed\n");
436                 return err;
437         }
438
439         ctx.comm = quadd_comm_events_init(&control);
440         if (!ctx.comm) {
441                 pr_err("error: COMM init failed\n");
442                 return -ENODEV;
443         }
444
445         err = quadd_auth_init(&ctx);
446         if (err < 0) {
447                 pr_err("error: auth failed\n");
448                 return err;
449         }
450
451         return 0;
452 }
453
454 static void __exit quadd_module_exit(void)
455 {
456         pr_info("QuadD module exit\n");
457
458         quadd_hrt_deinit();
459         quadd_mmap_deinit();
460         quadd_power_clk_deinit();
461         quadd_comm_events_exit();
462         quadd_auth_deinit();
463 }
464
465 module_init(quadd_module_init);
466 module_exit(quadd_module_exit);
467
468 MODULE_LICENSE("GPL");
469
470 MODULE_AUTHOR("Nvidia Ltd");
471 MODULE_DESCRIPTION("Tegra profiler");