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