]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/blob - drivers/misc/tegra-profiler/main.c
tegra-profiler: add access to the exception tables
[sojka/nv-tegra/linux-3.10.git] / drivers / misc / tegra-profiler / main.c
1 /*
2  * drivers/misc/tegra-profiler/main.c
3  *
4  * Copyright (c) 2014, 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 #include <linux/sched.h>
23
24 #include <linux/tegra_profiler.h>
25
26 #include "quadd.h"
27 #include "arm_pmu.h"
28 #include "hrt.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 #include "eh_unwind.h"
38
39 #ifdef CONFIG_ARM64
40 #include "armv8_pmu.h"
41 #else
42 #include "armv7_pmu.h"
43 #endif
44
45 #ifdef CONFIG_CACHE_L2X0
46 #include "pl310.h"
47 #endif
48
49 static struct quadd_ctx ctx;
50
51 static int get_default_properties(void)
52 {
53         ctx.param.freq = 100;
54         ctx.param.ma_freq = 50;
55         ctx.param.backtrace = 1;
56         ctx.param.use_freq = 1;
57         ctx.param.system_wide = 1;
58         ctx.param.power_rate_freq = 0;
59         ctx.param.debug_samples = 0;
60
61         ctx.param.pids[0] = 0;
62         ctx.param.nr_pids = 1;
63
64         return 0;
65 }
66
67 int tegra_profiler_try_lock(void)
68 {
69         return atomic_cmpxchg(&ctx.tegra_profiler_lock, 0, 1);
70 }
71 EXPORT_SYMBOL_GPL(tegra_profiler_try_lock);
72
73 void tegra_profiler_unlock(void)
74 {
75         atomic_set(&ctx.tegra_profiler_lock, 0);
76 }
77 EXPORT_SYMBOL_GPL(tegra_profiler_unlock);
78
79 static int start(void)
80 {
81         int err;
82
83         if (tegra_profiler_try_lock()) {
84                 pr_err("Error: tegra_profiler lock\n");
85                 return -EBUSY;
86         }
87
88         if (!atomic_cmpxchg(&ctx.started, 0, 1)) {
89                 if (ctx.pmu) {
90                         err = ctx.pmu->enable();
91                         if (err) {
92                                 pr_err("error: pmu enable\n");
93                                 goto errout;
94                         }
95                 }
96
97                 if (ctx.pl310) {
98                         err = ctx.pl310->enable();
99                         if (err) {
100                                 pr_err("error: pl310 enable\n");
101                                 goto errout;
102                         }
103                 }
104
105                 ctx.comm->reset();
106
107                 err = quadd_power_clk_start();
108                 if (err < 0) {
109                         pr_err("error: power_clk start\n");
110                         goto errout;
111                 }
112
113                 err = quadd_hrt_start();
114                 if (err) {
115                         pr_err("error: hrt start\n");
116                         goto errout;
117                 }
118         }
119
120         return 0;
121
122 errout:
123         atomic_set(&ctx.started, 0);
124         tegra_profiler_unlock();
125         return err;
126 }
127
128 static void stop(void)
129 {
130         if (atomic_cmpxchg(&ctx.started, 1, 0)) {
131                 quadd_hrt_stop();
132
133                 ctx.comm->reset();
134
135                 quadd_power_clk_stop();
136                 quadd_unwind_stop();
137
138                 if (ctx.pmu)
139                         ctx.pmu->disable();
140
141                 if (ctx.pl310)
142                         ctx.pl310->disable();
143
144                 tegra_profiler_unlock();
145         }
146 }
147
148 static inline int is_event_supported(struct source_info *si, int event)
149 {
150         int i;
151         int nr = si->nr_supported_events;
152         int *events = si->supported_events;
153
154         for (i = 0; i < nr; i++) {
155                 if (event == events[i])
156                         return 1;
157         }
158         return 0;
159 }
160
161 static int set_parameters(struct quadd_parameters *p, uid_t *debug_app_uid)
162 {
163         int i, err;
164         int pmu_events_id[QUADD_MAX_COUNTERS];
165         int pl310_events_id;
166         int nr_pmu = 0, nr_pl310 = 0;
167         int uid = 0;
168         struct task_struct *task;
169         unsigned int extra;
170
171         if (ctx.param.freq != 100 && ctx.param.freq != 1000 &&
172             ctx.param.freq != 10000)
173                 return -EINVAL;
174
175         ctx.param.freq = p->freq;
176         ctx.param.ma_freq = p->ma_freq;
177         ctx.param.backtrace = p->backtrace;
178         ctx.param.use_freq = p->use_freq;
179         ctx.param.system_wide = p->system_wide;
180         ctx.param.power_rate_freq = p->power_rate_freq;
181         ctx.param.debug_samples = p->debug_samples;
182
183         for (i = 0; i < ARRAY_SIZE(p->reserved); i++)
184                 ctx.param.reserved[i] = p->reserved[i];
185
186         /* Currently only one process */
187         if (p->nr_pids != 1)
188                 return -EINVAL;
189
190         rcu_read_lock();
191         task = pid_task(find_vpid(p->pids[0]), PIDTYPE_PID);
192         rcu_read_unlock();
193         if (!task) {
194                 pr_err("Process not found: %u\n", p->pids[0]);
195                 return -ESRCH;
196         }
197
198         pr_info("owner/task uids: %u/%u\n", current_fsuid(), task_uid(task));
199         if (!capable(CAP_SYS_ADMIN)) {
200                 if (current_fsuid() != task_uid(task)) {
201                         uid = quadd_auth_is_debuggable((char *)p->package_name);
202                         if (uid < 0) {
203                                 pr_err("Error: QuadD security service\n");
204                                 return uid;
205                         } else if (uid == 0) {
206                                 pr_err("Error: app is not debuggable\n");
207                                 return -EACCES;
208                         }
209
210                         *debug_app_uid = uid;
211                         pr_info("debug_app_uid: %u\n", uid);
212                 }
213                 ctx.collect_kernel_ips = 0;
214         } else {
215                 ctx.collect_kernel_ips = 1;
216         }
217
218         for (i = 0; i < p->nr_pids; i++)
219                 ctx.param.pids[i] = p->pids[i];
220
221         ctx.param.nr_pids = p->nr_pids;
222
223         for (i = 0; i < p->nr_events; i++) {
224                 int event = p->events[i];
225
226                 if (ctx.pmu && ctx.pmu_info.nr_supported_events > 0
227                         && is_event_supported(&ctx.pmu_info, event)) {
228                         pmu_events_id[nr_pmu++] = p->events[i];
229
230                         pr_info("PMU active event: %s\n",
231                                 quadd_get_event_str(event));
232                 } else if (ctx.pl310 &&
233                            ctx.pl310_info.nr_supported_events > 0 &&
234                            is_event_supported(&ctx.pl310_info, event)) {
235                         pl310_events_id = p->events[i];
236
237                         pr_info("PL310 active event: %s\n",
238                                 quadd_get_event_str(event));
239
240                         if (nr_pl310++ > 1) {
241                                 pr_err("error: multiply pl310 events\n");
242                                 return -EINVAL;
243                         }
244                 } else {
245                         pr_err("Bad event: %s\n",
246                                quadd_get_event_str(event));
247                         return -EINVAL;
248                 }
249         }
250
251         if (ctx.pmu) {
252                 if (nr_pmu > 0) {
253                         err = ctx.pmu->set_events(pmu_events_id, nr_pmu);
254                         if (err) {
255                                 pr_err("PMU set parameters: error\n");
256                                 return err;
257                         }
258                         ctx.pmu_info.active = 1;
259                 } else {
260                         ctx.pmu_info.active = 0;
261                         ctx.pmu->set_events(NULL, 0);
262                 }
263         }
264
265         if (ctx.pl310) {
266                 if (nr_pl310 == 1) {
267                         err = ctx.pl310->set_events(&pl310_events_id, 1);
268                         if (err) {
269                                 pr_info("pl310 set_parameters: error\n");
270                                 return err;
271                         }
272                         ctx.pl310_info.active = 1;
273                 } else {
274                         ctx.pl310_info.active = 0;
275                         ctx.pl310->set_events(NULL, 0);
276                 }
277         }
278
279         extra = p->reserved[QUADD_PARAM_IDX_EXTRA];
280
281         if (extra & QUADD_PARAM_EXTRA_BT_UNWIND_TABLES)
282                 pr_info("unwinding: exception-handling tables\n");
283
284         if (extra & QUADD_PARAM_EXTRA_BT_FP)
285                 pr_info("unwinding: frame pointers\n");
286
287         quadd_unwind_start(task);
288
289         pr_info("New parameters have been applied\n");
290
291         return 0;
292 }
293
294 static void get_capabilities(struct quadd_comm_cap *cap)
295 {
296         int i, event;
297         unsigned int extra = 0;
298         struct quadd_events_cap *events_cap = &cap->events_cap;
299
300         cap->pmu = ctx.pmu ? 1 : 0;
301
302         cap->l2_cache = 0;
303         if (ctx.pl310) {
304                 cap->l2_cache = 1;
305                 cap->l2_multiple_events = 0;
306         } else if (ctx.pmu) {
307                 struct source_info *s = &ctx.pmu_info;
308                 for (i = 0; i < s->nr_supported_events; i++) {
309                         event = s->supported_events[i];
310                         if (event == QUADD_EVENT_TYPE_L2_DCACHE_READ_MISSES ||
311                             event == QUADD_EVENT_TYPE_L2_DCACHE_WRITE_MISSES ||
312                             event == QUADD_EVENT_TYPE_L2_ICACHE_MISSES) {
313                                 cap->l2_cache = 1;
314                                 cap->l2_multiple_events = 1;
315                                 break;
316                         }
317                 }
318         }
319
320         events_cap->cpu_cycles = 0;
321         events_cap->l1_dcache_read_misses = 0;
322         events_cap->l1_dcache_write_misses = 0;
323         events_cap->l1_icache_misses = 0;
324
325         events_cap->instructions = 0;
326         events_cap->branch_instructions = 0;
327         events_cap->branch_misses = 0;
328         events_cap->bus_cycles = 0;
329
330         events_cap->l2_dcache_read_misses = 0;
331         events_cap->l2_dcache_write_misses = 0;
332         events_cap->l2_icache_misses = 0;
333
334         if (ctx.pl310) {
335                 struct source_info *s = &ctx.pl310_info;
336                 for (i = 0; i < s->nr_supported_events; i++) {
337                         int event = s->supported_events[i];
338
339                         switch (event) {
340                         case QUADD_EVENT_TYPE_L2_DCACHE_READ_MISSES:
341                                 events_cap->l2_dcache_read_misses = 1;
342                                 break;
343                         case QUADD_EVENT_TYPE_L2_DCACHE_WRITE_MISSES:
344                                 events_cap->l2_dcache_write_misses = 1;
345                                 break;
346                         case QUADD_EVENT_TYPE_L2_ICACHE_MISSES:
347                                 events_cap->l2_icache_misses = 1;
348                                 break;
349
350                         default:
351                                 pr_err_once("%s: error: invalid event\n",
352                                             __func__);
353                                 return;
354                         }
355                 }
356         }
357
358         if (ctx.pmu) {
359                 struct source_info *s = &ctx.pmu_info;
360                 for (i = 0; i < s->nr_supported_events; i++) {
361                         int event = s->supported_events[i];
362
363                         switch (event) {
364                         case QUADD_EVENT_TYPE_CPU_CYCLES:
365                                 events_cap->cpu_cycles = 1;
366                                 break;
367                         case QUADD_EVENT_TYPE_INSTRUCTIONS:
368                                 events_cap->instructions = 1;
369                                 break;
370                         case QUADD_EVENT_TYPE_BRANCH_INSTRUCTIONS:
371                                 events_cap->branch_instructions = 1;
372                                 break;
373                         case QUADD_EVENT_TYPE_BRANCH_MISSES:
374                                 events_cap->branch_misses = 1;
375                                 break;
376                         case QUADD_EVENT_TYPE_BUS_CYCLES:
377                                 events_cap->bus_cycles = 1;
378                                 break;
379
380                         case QUADD_EVENT_TYPE_L1_DCACHE_READ_MISSES:
381                                 events_cap->l1_dcache_read_misses = 1;
382                                 break;
383                         case QUADD_EVENT_TYPE_L1_DCACHE_WRITE_MISSES:
384                                 events_cap->l1_dcache_write_misses = 1;
385                                 break;
386                         case QUADD_EVENT_TYPE_L1_ICACHE_MISSES:
387                                 events_cap->l1_icache_misses = 1;
388                                 break;
389
390                         case QUADD_EVENT_TYPE_L2_DCACHE_READ_MISSES:
391                                 events_cap->l2_dcache_read_misses = 1;
392                                 break;
393                         case QUADD_EVENT_TYPE_L2_DCACHE_WRITE_MISSES:
394                                 events_cap->l2_dcache_write_misses = 1;
395                                 break;
396                         case QUADD_EVENT_TYPE_L2_ICACHE_MISSES:
397                                 events_cap->l2_icache_misses = 1;
398                                 break;
399
400                         default:
401                                 pr_err_once("%s: error: invalid event\n",
402                                             __func__);
403                                 return;
404                         }
405                 }
406         }
407
408         cap->tegra_lp_cluster = quadd_is_cpu_with_lp_cluster();
409         cap->power_rate = 1;
410         cap->blocked_read = 1;
411
412         extra |= QUADD_COMM_CAP_EXTRA_BT_KERNEL_CTX;
413         extra |= QUADD_COMM_CAP_EXTRA_GET_MMAP;
414         extra |= QUADD_COMM_CAP_EXTRA_GROUP_SAMPLES;
415         extra |= QUADD_COMM_CAP_EXTRA_BT_UNWIND_TABLES;
416         extra |= QUADD_COMM_CAP_EXTRA_SUPPORT_AARCH64;
417         extra |= QUADD_COMM_CAP_EXTRA_SPECIAL_ARCH_MMAP;
418         extra |= QUADD_COMM_CAP_EXTRA_UNWIND_MIXED;
419
420         cap->reserved[QUADD_COMM_CAP_IDX_EXTRA] = extra;
421 }
422
423 void quadd_get_state(struct quadd_module_state *state)
424 {
425         unsigned int status = 0;
426
427         quadd_hrt_get_state(state);
428
429         if (ctx.comm->is_active())
430                 status |= QUADD_MOD_STATE_STATUS_IS_ACTIVE;
431
432         if (quadd_auth_is_auth_open())
433                 status |= QUADD_MOD_STATE_STATUS_IS_AUTH_OPEN;
434
435         state->reserved[QUADD_MOD_STATE_IDX_STATUS] = status;
436 }
437
438 static int
439 set_extab(struct quadd_extables *extabs,
440           struct quadd_extabs_mmap *mmap)
441 {
442         return quadd_unwind_set_extab(extabs, mmap);
443 }
444
445 static void
446 delete_mmap(struct quadd_extabs_mmap *mmap)
447 {
448         quadd_unwind_delete_mmap(mmap);
449 }
450
451 static struct quadd_comm_control_interface control = {
452         .start                  = start,
453         .stop                   = stop,
454         .set_parameters         = set_parameters,
455         .get_capabilities       = get_capabilities,
456         .get_state              = quadd_get_state,
457         .set_extab              = set_extab,
458         .delete_mmap            = delete_mmap,
459 };
460
461 static int __init quadd_module_init(void)
462 {
463         int i, nr_events, err;
464         int *events;
465
466         pr_info("Branch: %s\n", QUADD_MODULE_BRANCH);
467         pr_info("Version: %s\n", QUADD_MODULE_VERSION);
468         pr_info("Samples version: %d\n", QUADD_SAMPLES_VERSION);
469         pr_info("IO version: %d\n", QUADD_IO_VERSION);
470
471 #ifdef QM_DEBUG_SAMPLES_ENABLE
472         pr_info("############## DEBUG VERSION! ##############\n");
473 #endif
474
475         atomic_set(&ctx.started, 0);
476         atomic_set(&ctx.tegra_profiler_lock, 0);
477
478         get_default_properties();
479
480         ctx.pmu_info.active = 0;
481         ctx.pl310_info.active = 0;
482
483 #ifdef CONFIG_ARM64
484         ctx.pmu = quadd_armv8_pmu_init();
485 #else
486         ctx.pmu = quadd_armv7_pmu_init();
487 #endif
488         if (!ctx.pmu) {
489                 pr_err("PMU init failed\n");
490                 return -ENODEV;
491         } else {
492                 events = ctx.pmu_info.supported_events;
493                 nr_events = ctx.pmu->get_supported_events(events,
494                                                           QUADD_MAX_COUNTERS);
495                 ctx.pmu_info.nr_supported_events = nr_events;
496
497                 pr_info("PMU: amount of events: %d\n", nr_events);
498
499                 for (i = 0; i < nr_events; i++)
500                         pr_info("PMU event: %s\n",
501                                 quadd_get_event_str(events[i]));
502         }
503
504 #ifdef CONFIG_CACHE_L2X0
505         ctx.pl310 = quadd_l2x0_events_init();
506 #else
507         ctx.pl310 = NULL;
508 #endif
509         if (ctx.pl310) {
510                 events = ctx.pl310_info.supported_events;
511                 nr_events = ctx.pl310->get_supported_events(events,
512                                                             QUADD_MAX_COUNTERS);
513                 ctx.pl310_info.nr_supported_events = nr_events;
514
515                 pr_info("pl310 success, amount of events: %d\n",
516                         nr_events);
517
518                 for (i = 0; i < nr_events; i++)
519                         pr_info("pl310 event: %s\n",
520                                 quadd_get_event_str(events[i]));
521         } else {
522                 pr_info("PL310 not found\n");
523         }
524
525         ctx.hrt = quadd_hrt_init(&ctx);
526         if (IS_ERR(ctx.hrt)) {
527                 pr_err("error: HRT init failed\n");
528                 return PTR_ERR(ctx.hrt);
529         }
530
531         err = quadd_power_clk_init(&ctx);
532         if (err < 0) {
533                 pr_err("error: POWER CLK init failed\n");
534                 return err;
535         }
536
537         ctx.comm = quadd_comm_events_init(&control);
538         if (IS_ERR(ctx.comm)) {
539                 pr_err("error: COMM init failed\n");
540                 return PTR_ERR(ctx.comm);
541         }
542
543         err = quadd_auth_init(&ctx);
544         if (err < 0) {
545                 pr_err("error: auth failed\n");
546                 return err;
547         }
548
549         err = quadd_unwind_init();
550         if (err < 0) {
551                 pr_err("error: EH unwinding init failed\n");
552                 return err;
553         }
554
555         get_capabilities(&ctx.cap);
556         quadd_proc_init(&ctx);
557
558         return 0;
559 }
560
561 static void __exit quadd_module_exit(void)
562 {
563         pr_info("QuadD module exit\n");
564
565         quadd_hrt_deinit();
566         quadd_power_clk_deinit();
567         quadd_comm_events_exit();
568         quadd_auth_deinit();
569         quadd_proc_deinit();
570         quadd_unwind_deinit();
571
572 #ifdef CONFIG_ARM64
573         quadd_armv8_pmu_deinit();
574 #else
575         quadd_armv7_pmu_deinit();
576 #endif
577 }
578
579 module_init(quadd_module_init);
580 module_exit(quadd_module_exit);
581
582 MODULE_LICENSE("GPL");
583
584 MODULE_AUTHOR("Nvidia Ltd");
585 MODULE_DESCRIPTION("Tegra profiler");