misc: tegra-profiler: Do not expose kernel IPs
[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                 ctx.collect_kernel_ips = 0;
174         } else {
175                 ctx.collect_kernel_ips = 1;
176         }
177
178         for (i = 0; i < param->nr_pids; i++)
179                 ctx.param.pids[i] = param->pids[i];
180
181         ctx.param.nr_pids = param->nr_pids;
182
183         for (i = 0; i < param->nr_events; i++) {
184                 int event = param->events[i];
185
186                 if (ctx.pmu && ctx.pmu_info.nr_supported_events > 0
187                         && is_event_supported(&ctx.pmu_info, event)) {
188                         pmu_events_id[nr_pmu++] = param->events[i];
189
190                         pr_info("PMU active event: %s\n",
191                                 quadd_get_event_str(event));
192                 } else if (ctx.pl310 &&
193                            ctx.pl310_info.nr_supported_events > 0 &&
194                            is_event_supported(&ctx.pl310_info, event)) {
195                         pl310_events_id = param->events[i];
196
197                         pr_info("PL310 active event: %s\n",
198                                 quadd_get_event_str(event));
199
200                         if (nr_pl310++ > 1) {
201                                 pr_err("error: multiply pl310 events\n");
202                                 return -EINVAL;
203                         }
204                 } else {
205                         pr_err("Bad event: %s\n",
206                                quadd_get_event_str(event));
207                         return -EINVAL;
208                 }
209         }
210
211         if (ctx.pmu) {
212                 if (nr_pmu > 0) {
213                         err = ctx.pmu->set_events(pmu_events_id, nr_pmu);
214                         if (err) {
215                                 pr_err("PMU set parameters: error\n");
216                                 return err;
217                         }
218                         ctx.pmu_info.active = 1;
219                 } else {
220                         ctx.pmu_info.active = 0;
221                         ctx.pmu->set_events(NULL, 0);
222                 }
223         }
224
225         if (ctx.pl310) {
226                 if (nr_pl310 == 1) {
227                         err = ctx.pl310->set_events(&pl310_events_id, 1);
228                         if (err) {
229                                 pr_info("pl310 set_parameters: error\n");
230                                 return err;
231                         }
232                         ctx.pl310_info.active = 1;
233                 } else {
234                         ctx.pl310_info.active = 0;
235                         ctx.pl310->set_events(NULL, 0);
236                 }
237         }
238         pr_info("New parameters have been applied\n");
239
240         return 0;
241 }
242
243 static void get_capabilities(struct quadd_comm_cap *cap)
244 {
245         int i, event;
246         struct quadd_events_cap *events_cap = &cap->events_cap;
247
248         cap->pmu = ctx.pmu ? 1 : 0;
249
250         cap->l2_cache = 0;
251         if (ctx.pl310) {
252                 cap->l2_cache = 1;
253                 cap->l2_multiple_events = 0;
254         } else if (ctx.pmu) {
255                 struct source_info *s = &ctx.pmu_info;
256                 for (i = 0; i < s->nr_supported_events; i++) {
257                         event = s->supported_events[i];
258                         if (event == QUADD_EVENT_TYPE_L2_DCACHE_READ_MISSES ||
259                             event == QUADD_EVENT_TYPE_L2_DCACHE_WRITE_MISSES ||
260                             event == QUADD_EVENT_TYPE_L2_ICACHE_MISSES) {
261                                 cap->l2_cache = 1;
262                                 cap->l2_multiple_events = 1;
263                                 break;
264                         }
265                 }
266         }
267
268         events_cap->cpu_cycles = 0;
269         events_cap->l1_dcache_read_misses = 0;
270         events_cap->l1_dcache_write_misses = 0;
271         events_cap->l1_icache_misses = 0;
272
273         events_cap->instructions = 0;
274         events_cap->branch_instructions = 0;
275         events_cap->branch_misses = 0;
276         events_cap->bus_cycles = 0;
277
278         events_cap->l2_dcache_read_misses = 0;
279         events_cap->l2_dcache_write_misses = 0;
280         events_cap->l2_icache_misses = 0;
281
282         if (ctx.pl310) {
283                 struct source_info *s = &ctx.pl310_info;
284                 for (i = 0; i < s->nr_supported_events; i++) {
285                         int event = s->supported_events[i];
286
287                         switch (event) {
288                         case QUADD_EVENT_TYPE_L2_DCACHE_READ_MISSES:
289                                 events_cap->l2_dcache_read_misses = 1;
290                                 break;
291                         case QUADD_EVENT_TYPE_L2_DCACHE_WRITE_MISSES:
292                                 events_cap->l2_dcache_write_misses = 1;
293                                 break;
294                         case QUADD_EVENT_TYPE_L2_ICACHE_MISSES:
295                                 events_cap->l2_icache_misses = 1;
296                                 break;
297
298                         default:
299                                 BUG();
300                                 break;
301                         }
302                 }
303         }
304
305         if (ctx.pmu) {
306                 struct source_info *s = &ctx.pmu_info;
307                 for (i = 0; i < s->nr_supported_events; i++) {
308                         int event = s->supported_events[i];
309
310                         switch (event) {
311                         case QUADD_EVENT_TYPE_CPU_CYCLES:
312                                 events_cap->cpu_cycles = 1;
313                                 break;
314                         case QUADD_EVENT_TYPE_INSTRUCTIONS:
315                                 events_cap->instructions = 1;
316                                 break;
317                         case QUADD_EVENT_TYPE_BRANCH_INSTRUCTIONS:
318                                 events_cap->branch_instructions = 1;
319                                 break;
320                         case QUADD_EVENT_TYPE_BRANCH_MISSES:
321                                 events_cap->branch_misses = 1;
322                                 break;
323                         case QUADD_EVENT_TYPE_BUS_CYCLES:
324                                 events_cap->bus_cycles = 1;
325                                 break;
326
327                         case QUADD_EVENT_TYPE_L1_DCACHE_READ_MISSES:
328                                 events_cap->l1_dcache_read_misses = 1;
329                                 break;
330                         case QUADD_EVENT_TYPE_L1_DCACHE_WRITE_MISSES:
331                                 events_cap->l1_dcache_write_misses = 1;
332                                 break;
333                         case QUADD_EVENT_TYPE_L1_ICACHE_MISSES:
334                                 events_cap->l1_icache_misses = 1;
335                                 break;
336
337                         case QUADD_EVENT_TYPE_L2_DCACHE_READ_MISSES:
338                                 events_cap->l2_dcache_read_misses = 1;
339                                 break;
340                         case QUADD_EVENT_TYPE_L2_DCACHE_WRITE_MISSES:
341                                 events_cap->l2_dcache_write_misses = 1;
342                                 break;
343                         case QUADD_EVENT_TYPE_L2_ICACHE_MISSES:
344                                 events_cap->l2_icache_misses = 1;
345                                 break;
346
347                         default:
348                                 BUG();
349                                 break;
350                         }
351                 }
352         }
353
354         cap->tegra_lp_cluster = quadd_is_cpu_with_lp_cluster();
355         cap->power_rate = 1;
356         cap->blocked_read = 0;
357 }
358
359 static void get_state(struct quadd_module_state *state)
360 {
361         quadd_hrt_get_state(state);
362 }
363
364 static struct quadd_comm_control_interface control = {
365         .start                  = start,
366         .stop                   = stop,
367         .set_parameters         = set_parameters,
368         .get_capabilities       = get_capabilities,
369         .get_state              = get_state,
370 };
371
372 static int __init quadd_module_init(void)
373 {
374         int i, nr_events, err;
375         int *events;
376
377         pr_info("Branch: %s\n", QUADD_MODULE_BRANCH);
378         pr_info("Version: %s\n", QUADD_MODULE_VERSION);
379         pr_info("Samples version: %d\n", QUADD_SAMPLES_VERSION);
380         pr_info("IO version: %d\n", QUADD_IO_VERSION);
381
382 #ifdef QM_DEBUG_SAMPLES_ENABLE
383         pr_info("############## DEBUG VERSION! ##############\n");
384 #endif
385         atomic_set(&ctx.started, 0);
386
387         get_default_properties();
388
389         ctx.pmu_info.active = 0;
390         ctx.pl310_info.active = 0;
391
392         ctx.pmu = quadd_armv7_pmu_init();
393         if (!ctx.pmu) {
394                 pr_err("PMU init failed\n");
395                 return -ENODEV;
396         } else {
397                 events = ctx.pmu_info.supported_events;
398                 nr_events = ctx.pmu->get_supported_events(events);
399                 ctx.pmu_info.nr_supported_events = nr_events;
400
401                 pr_info("PMU: amount of events: %d\n", nr_events);
402
403                 for (i = 0; i < nr_events; i++)
404                         pr_info("PMU event: %s\n",
405                                 quadd_get_event_str(events[i]));
406         }
407
408         ctx.pl310 = quadd_l2x0_events_init();
409         if (ctx.pl310) {
410                 events = ctx.pl310_info.supported_events;
411                 nr_events = ctx.pl310->get_supported_events(events);
412                 ctx.pl310_info.nr_supported_events = nr_events;
413
414                 pr_info("pl310 success, amount of events: %d\n",
415                         nr_events);
416
417                 for (i = 0; i < nr_events; i++)
418                         pr_info("pl310 event: %s\n",
419                                 quadd_get_event_str(events[i]));
420         } else {
421                 pr_info("PL310 not found\n");
422         }
423
424         ctx.hrt = quadd_hrt_init(&ctx);
425         if (!ctx.hrt) {
426                 pr_err("error: HRT init failed\n");
427                 return -ENODEV;
428         }
429
430         ctx.mmap = quadd_mmap_init(&ctx);
431         if (!ctx.mmap) {
432                 pr_err("error: MMAP init failed\n");
433                 return -ENODEV;
434         }
435
436         err = quadd_power_clk_init(&ctx);
437         if (err < 0) {
438                 pr_err("error: POWER CLK init failed\n");
439                 return err;
440         }
441
442         ctx.comm = quadd_comm_events_init(&control);
443         if (!ctx.comm) {
444                 pr_err("error: COMM init failed\n");
445                 return -ENODEV;
446         }
447
448         err = quadd_auth_init(&ctx);
449         if (err < 0) {
450                 pr_err("error: auth failed\n");
451                 return err;
452         }
453
454         return 0;
455 }
456
457 static void __exit quadd_module_exit(void)
458 {
459         pr_info("QuadD module exit\n");
460
461         quadd_hrt_deinit();
462         quadd_mmap_deinit();
463         quadd_power_clk_deinit();
464         quadd_comm_events_exit();
465         quadd_auth_deinit();
466 }
467
468 module_init(quadd_module_init);
469 module_exit(quadd_module_exit);
470
471 MODULE_LICENSE("GPL");
472
473 MODULE_AUTHOR("Nvidia Ltd");
474 MODULE_DESCRIPTION("Tegra profiler");