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