]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/blob - drivers/misc/tegra-profiler/main.c
misc: tegra-profiler: fix setup bug
[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
162 validate_freq(unsigned int freq)
163 {
164         if (capable(CAP_SYS_ADMIN))
165                 return freq >= 100 && freq <= 100000;
166         else
167                 return freq == 100 || freq == 1000 || freq == 10000;
168 }
169
170 static int
171 set_parameters(struct quadd_parameters *p, uid_t *debug_app_uid)
172 {
173         int i, err;
174         int pmu_events_id[QUADD_MAX_COUNTERS];
175         int pl310_events_id;
176         int nr_pmu = 0, nr_pl310 = 0;
177         int uid = 0;
178         struct task_struct *task;
179         unsigned int extra;
180
181         if (!validate_freq(p->freq)) {
182                 pr_err("%s: incorrect frequency: %u", __func__, p->freq);
183                 return -EINVAL;
184         }
185
186         ctx.param.freq = p->freq;
187         ctx.param.ma_freq = p->ma_freq;
188         ctx.param.backtrace = p->backtrace;
189         ctx.param.use_freq = p->use_freq;
190         ctx.param.system_wide = p->system_wide;
191         ctx.param.power_rate_freq = p->power_rate_freq;
192         ctx.param.debug_samples = p->debug_samples;
193
194         for (i = 0; i < ARRAY_SIZE(p->reserved); i++)
195                 ctx.param.reserved[i] = p->reserved[i];
196
197         /* Currently only one process */
198         if (p->nr_pids != 1)
199                 return -EINVAL;
200
201         rcu_read_lock();
202         task = pid_task(find_vpid(p->pids[0]), PIDTYPE_PID);
203         rcu_read_unlock();
204         if (!task) {
205                 pr_err("Process not found: %u\n", p->pids[0]);
206                 return -ESRCH;
207         }
208
209         pr_info("owner/task uids: %u/%u\n", current_fsuid(), task_uid(task));
210         if (!capable(CAP_SYS_ADMIN)) {
211                 if (current_fsuid() != task_uid(task)) {
212                         uid = quadd_auth_is_debuggable((char *)p->package_name);
213                         if (uid < 0) {
214                                 pr_err("Error: QuadD security service\n");
215                                 return uid;
216                         } else if (uid == 0) {
217                                 pr_err("Error: app is not debuggable\n");
218                                 return -EACCES;
219                         }
220
221                         *debug_app_uid = uid;
222                         pr_info("debug_app_uid: %u\n", uid);
223                 }
224                 ctx.collect_kernel_ips = 0;
225         } else {
226                 ctx.collect_kernel_ips = 1;
227         }
228
229         for (i = 0; i < p->nr_pids; i++)
230                 ctx.param.pids[i] = p->pids[i];
231
232         ctx.param.nr_pids = p->nr_pids;
233
234         for (i = 0; i < p->nr_events; i++) {
235                 int event = p->events[i];
236
237                 if (ctx.pmu && ctx.pmu_info.nr_supported_events > 0
238                         && is_event_supported(&ctx.pmu_info, event)) {
239                         pmu_events_id[nr_pmu++] = p->events[i];
240
241                         pr_info("PMU active event: %s\n",
242                                 quadd_get_event_str(event));
243                 } else if (ctx.pl310 &&
244                            ctx.pl310_info.nr_supported_events > 0 &&
245                            is_event_supported(&ctx.pl310_info, event)) {
246                         pl310_events_id = p->events[i];
247
248                         pr_info("PL310 active event: %s\n",
249                                 quadd_get_event_str(event));
250
251                         if (nr_pl310++ > 1) {
252                                 pr_err("error: multiply pl310 events\n");
253                                 return -EINVAL;
254                         }
255                 } else {
256                         pr_err("Bad event: %s\n",
257                                quadd_get_event_str(event));
258                         return -EINVAL;
259                 }
260         }
261
262         if (ctx.pmu) {
263                 if (nr_pmu > 0) {
264                         err = ctx.pmu->set_events(pmu_events_id, nr_pmu);
265                         if (err) {
266                                 pr_err("PMU set parameters: error\n");
267                                 return err;
268                         }
269                         ctx.pmu_info.active = 1;
270                 } else {
271                         ctx.pmu_info.active = 0;
272                         ctx.pmu->set_events(NULL, 0);
273                 }
274         }
275
276         if (ctx.pl310) {
277                 if (nr_pl310 == 1) {
278                         err = ctx.pl310->set_events(&pl310_events_id, 1);
279                         if (err) {
280                                 pr_info("pl310 set_parameters: error\n");
281                                 return err;
282                         }
283                         ctx.pl310_info.active = 1;
284                 } else {
285                         ctx.pl310_info.active = 0;
286                         ctx.pl310->set_events(NULL, 0);
287                 }
288         }
289
290         extra = p->reserved[QUADD_PARAM_IDX_EXTRA];
291
292         if (extra & QUADD_PARAM_EXTRA_BT_UNWIND_TABLES)
293                 pr_info("unwinding: exception-handling tables\n");
294
295         if (extra & QUADD_PARAM_EXTRA_BT_FP)
296                 pr_info("unwinding: frame pointers\n");
297
298         if (extra & QUADD_PARAM_EXTRA_BT_MIXED)
299                 pr_info("unwinding: mixed mode\n");
300
301         quadd_unwind_start(task);
302
303         pr_info("New parameters have been applied\n");
304
305         return 0;
306 }
307
308 static void get_capabilities(struct quadd_comm_cap *cap)
309 {
310         int i, event;
311         unsigned int extra = 0;
312         struct quadd_events_cap *events_cap = &cap->events_cap;
313
314         cap->pmu = ctx.pmu ? 1 : 0;
315
316         cap->l2_cache = 0;
317         if (ctx.pl310) {
318                 cap->l2_cache = 1;
319                 cap->l2_multiple_events = 0;
320         } else if (ctx.pmu) {
321                 struct source_info *s = &ctx.pmu_info;
322                 for (i = 0; i < s->nr_supported_events; i++) {
323                         event = s->supported_events[i];
324                         if (event == QUADD_EVENT_TYPE_L2_DCACHE_READ_MISSES ||
325                             event == QUADD_EVENT_TYPE_L2_DCACHE_WRITE_MISSES ||
326                             event == QUADD_EVENT_TYPE_L2_ICACHE_MISSES) {
327                                 cap->l2_cache = 1;
328                                 cap->l2_multiple_events = 1;
329                                 break;
330                         }
331                 }
332         }
333
334         events_cap->cpu_cycles = 0;
335         events_cap->l1_dcache_read_misses = 0;
336         events_cap->l1_dcache_write_misses = 0;
337         events_cap->l1_icache_misses = 0;
338
339         events_cap->instructions = 0;
340         events_cap->branch_instructions = 0;
341         events_cap->branch_misses = 0;
342         events_cap->bus_cycles = 0;
343
344         events_cap->l2_dcache_read_misses = 0;
345         events_cap->l2_dcache_write_misses = 0;
346         events_cap->l2_icache_misses = 0;
347
348         if (ctx.pl310) {
349                 struct source_info *s = &ctx.pl310_info;
350                 for (i = 0; i < s->nr_supported_events; i++) {
351                         int event = s->supported_events[i];
352
353                         switch (event) {
354                         case QUADD_EVENT_TYPE_L2_DCACHE_READ_MISSES:
355                                 events_cap->l2_dcache_read_misses = 1;
356                                 break;
357                         case QUADD_EVENT_TYPE_L2_DCACHE_WRITE_MISSES:
358                                 events_cap->l2_dcache_write_misses = 1;
359                                 break;
360                         case QUADD_EVENT_TYPE_L2_ICACHE_MISSES:
361                                 events_cap->l2_icache_misses = 1;
362                                 break;
363
364                         default:
365                                 pr_err_once("%s: error: invalid event\n",
366                                             __func__);
367                                 return;
368                         }
369                 }
370         }
371
372         if (ctx.pmu) {
373                 struct source_info *s = &ctx.pmu_info;
374                 for (i = 0; i < s->nr_supported_events; i++) {
375                         int event = s->supported_events[i];
376
377                         switch (event) {
378                         case QUADD_EVENT_TYPE_CPU_CYCLES:
379                                 events_cap->cpu_cycles = 1;
380                                 break;
381                         case QUADD_EVENT_TYPE_INSTRUCTIONS:
382                                 events_cap->instructions = 1;
383                                 break;
384                         case QUADD_EVENT_TYPE_BRANCH_INSTRUCTIONS:
385                                 events_cap->branch_instructions = 1;
386                                 break;
387                         case QUADD_EVENT_TYPE_BRANCH_MISSES:
388                                 events_cap->branch_misses = 1;
389                                 break;
390                         case QUADD_EVENT_TYPE_BUS_CYCLES:
391                                 events_cap->bus_cycles = 1;
392                                 break;
393
394                         case QUADD_EVENT_TYPE_L1_DCACHE_READ_MISSES:
395                                 events_cap->l1_dcache_read_misses = 1;
396                                 break;
397                         case QUADD_EVENT_TYPE_L1_DCACHE_WRITE_MISSES:
398                                 events_cap->l1_dcache_write_misses = 1;
399                                 break;
400                         case QUADD_EVENT_TYPE_L1_ICACHE_MISSES:
401                                 events_cap->l1_icache_misses = 1;
402                                 break;
403
404                         case QUADD_EVENT_TYPE_L2_DCACHE_READ_MISSES:
405                                 events_cap->l2_dcache_read_misses = 1;
406                                 break;
407                         case QUADD_EVENT_TYPE_L2_DCACHE_WRITE_MISSES:
408                                 events_cap->l2_dcache_write_misses = 1;
409                                 break;
410                         case QUADD_EVENT_TYPE_L2_ICACHE_MISSES:
411                                 events_cap->l2_icache_misses = 1;
412                                 break;
413
414                         default:
415                                 pr_err_once("%s: error: invalid event\n",
416                                             __func__);
417                                 return;
418                         }
419                 }
420         }
421
422         cap->tegra_lp_cluster = quadd_is_cpu_with_lp_cluster();
423         cap->power_rate = 1;
424         cap->blocked_read = 1;
425
426         extra |= QUADD_COMM_CAP_EXTRA_BT_KERNEL_CTX;
427         extra |= QUADD_COMM_CAP_EXTRA_GET_MMAP;
428         extra |= QUADD_COMM_CAP_EXTRA_GROUP_SAMPLES;
429         extra |= QUADD_COMM_CAP_EXTRA_BT_UNWIND_TABLES;
430         extra |= QUADD_COMM_CAP_EXTRA_SUPPORT_AARCH64;
431         extra |= QUADD_COMM_CAP_EXTRA_SPECIAL_ARCH_MMAP;
432         extra |= QUADD_COMM_CAP_EXTRA_UNWIND_MIXED;
433
434         cap->reserved[QUADD_COMM_CAP_IDX_EXTRA] = extra;
435 }
436
437 void quadd_get_state(struct quadd_module_state *state)
438 {
439         unsigned int status = 0;
440
441         quadd_hrt_get_state(state);
442
443         if (ctx.comm->is_active())
444                 status |= QUADD_MOD_STATE_STATUS_IS_ACTIVE;
445
446         if (quadd_auth_is_auth_open())
447                 status |= QUADD_MOD_STATE_STATUS_IS_AUTH_OPEN;
448
449         state->reserved[QUADD_MOD_STATE_IDX_STATUS] = status;
450 }
451
452 static int
453 set_extab(struct quadd_extables *extabs,
454           struct quadd_extabs_mmap *mmap)
455 {
456         return quadd_unwind_set_extab(extabs, mmap);
457 }
458
459 static void
460 delete_mmap(struct quadd_extabs_mmap *mmap)
461 {
462         quadd_unwind_delete_mmap(mmap);
463 }
464
465 static struct quadd_comm_control_interface control = {
466         .start                  = start,
467         .stop                   = stop,
468         .set_parameters         = set_parameters,
469         .get_capabilities       = get_capabilities,
470         .get_state              = quadd_get_state,
471         .set_extab              = set_extab,
472         .delete_mmap            = delete_mmap,
473 };
474
475 static int __init quadd_module_init(void)
476 {
477         int i, nr_events, err;
478         int *events;
479
480         pr_info("Branch: %s\n", QUADD_MODULE_BRANCH);
481         pr_info("Version: %s\n", QUADD_MODULE_VERSION);
482         pr_info("Samples version: %d\n", QUADD_SAMPLES_VERSION);
483         pr_info("IO version: %d\n", QUADD_IO_VERSION);
484
485 #ifdef QM_DEBUG_SAMPLES_ENABLE
486         pr_info("############## DEBUG VERSION! ##############\n");
487 #endif
488
489         atomic_set(&ctx.started, 0);
490         atomic_set(&ctx.tegra_profiler_lock, 0);
491
492         get_default_properties();
493
494         ctx.pmu_info.active = 0;
495         ctx.pl310_info.active = 0;
496
497 #ifdef CONFIG_ARM64
498         ctx.pmu = quadd_armv8_pmu_init();
499 #else
500         ctx.pmu = quadd_armv7_pmu_init();
501 #endif
502         if (!ctx.pmu) {
503                 pr_err("PMU init failed\n");
504                 return -ENODEV;
505         } else {
506                 events = ctx.pmu_info.supported_events;
507                 nr_events = ctx.pmu->get_supported_events(events,
508                                                           QUADD_MAX_COUNTERS);
509                 ctx.pmu_info.nr_supported_events = nr_events;
510
511                 pr_info("PMU: amount of events: %d\n", nr_events);
512
513                 for (i = 0; i < nr_events; i++)
514                         pr_info("PMU event: %s\n",
515                                 quadd_get_event_str(events[i]));
516         }
517
518 #ifdef CONFIG_CACHE_L2X0
519         ctx.pl310 = quadd_l2x0_events_init();
520 #else
521         ctx.pl310 = NULL;
522 #endif
523         if (ctx.pl310) {
524                 events = ctx.pl310_info.supported_events;
525                 nr_events = ctx.pl310->get_supported_events(events,
526                                                             QUADD_MAX_COUNTERS);
527                 ctx.pl310_info.nr_supported_events = nr_events;
528
529                 pr_info("pl310 success, amount of events: %d\n",
530                         nr_events);
531
532                 for (i = 0; i < nr_events; i++)
533                         pr_info("pl310 event: %s\n",
534                                 quadd_get_event_str(events[i]));
535         } else {
536                 pr_info("PL310 not found\n");
537         }
538
539         ctx.hrt = quadd_hrt_init(&ctx);
540         if (IS_ERR(ctx.hrt)) {
541                 pr_err("error: HRT init failed\n");
542                 return PTR_ERR(ctx.hrt);
543         }
544
545         err = quadd_power_clk_init(&ctx);
546         if (err < 0) {
547                 pr_err("error: POWER CLK init failed\n");
548                 return err;
549         }
550
551         ctx.comm = quadd_comm_events_init(&control);
552         if (IS_ERR(ctx.comm)) {
553                 pr_err("error: COMM init failed\n");
554                 return PTR_ERR(ctx.comm);
555         }
556
557         err = quadd_auth_init(&ctx);
558         if (err < 0) {
559                 pr_err("error: auth failed\n");
560                 return err;
561         }
562
563         err = quadd_unwind_init();
564         if (err < 0) {
565                 pr_err("error: EH unwinding init failed\n");
566                 return err;
567         }
568
569         get_capabilities(&ctx.cap);
570         quadd_proc_init(&ctx);
571
572         return 0;
573 }
574
575 static void __exit quadd_module_exit(void)
576 {
577         pr_info("QuadD module exit\n");
578
579         quadd_hrt_deinit();
580         quadd_power_clk_deinit();
581         quadd_comm_events_exit();
582         quadd_auth_deinit();
583         quadd_proc_deinit();
584         quadd_unwind_deinit();
585
586 #ifdef CONFIG_ARM64
587         quadd_armv8_pmu_deinit();
588 #else
589         quadd_armv7_pmu_deinit();
590 #endif
591 }
592
593 module_init(quadd_module_init);
594 module_exit(quadd_module_exit);
595
596 MODULE_LICENSE("GPL");
597
598 MODULE_AUTHOR("Nvidia Ltd");
599 MODULE_DESCRIPTION("Tegra profiler");