misc: tegra-profiler: support raw hardware events
[linux-3.10.git] / drivers / misc / tegra-profiler / main.c
1 /*
2  * drivers/misc/tegra-profiler/main.c
3  *
4  * Copyright (c) 2013-2017, 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 static DEFINE_PER_CPU(struct source_info, ctx_pmu_info);
51 static DEFINE_PER_CPU(struct quadd_comm_cap_for_cpu, per_cpu_caps);
52
53 static struct source_info *get_pmu_info_for_current_cpu(void)
54 {
55         return &__get_cpu_var(ctx_pmu_info);
56 }
57
58 static struct quadd_comm_cap_for_cpu *get_capabilities_for_cpu_int(int cpuid)
59 {
60         return &per_cpu(per_cpu_caps, cpuid);
61 }
62
63 static int get_default_properties(void)
64 {
65         ctx.param.freq = 100;
66         ctx.param.ma_freq = 50;
67         ctx.param.backtrace = 1;
68         ctx.param.use_freq = 1;
69         ctx.param.system_wide = 1;
70         ctx.param.power_rate_freq = 0;
71         ctx.param.debug_samples = 0;
72
73         ctx.param.pids[0] = 0;
74         ctx.param.nr_pids = 1;
75         ctx.get_capabilities_for_cpu = get_capabilities_for_cpu_int;
76         ctx.get_pmu_info = get_pmu_info_for_current_cpu;
77
78         return 0;
79 }
80
81 int tegra_profiler_try_lock(void)
82 {
83         return atomic_cmpxchg(&ctx.tegra_profiler_lock, 0, 1);
84 }
85 EXPORT_SYMBOL_GPL(tegra_profiler_try_lock);
86
87 void tegra_profiler_unlock(void)
88 {
89         atomic_set(&ctx.tegra_profiler_lock, 0);
90 }
91 EXPORT_SYMBOL_GPL(tegra_profiler_unlock);
92
93 static int start(void)
94 {
95         int err;
96
97         if (tegra_profiler_try_lock()) {
98                 pr_err("Error: tegra_profiler lock\n");
99                 return -EBUSY;
100         }
101
102         if (!atomic_cmpxchg(&ctx.started, 0, 1)) {
103                 preempt_disable();
104
105                 if (ctx.pmu) {
106                         err = ctx.pmu->enable();
107                         if (err) {
108                                 pr_err("error: pmu enable\n");
109                                 goto errout_preempt;
110                         }
111                 }
112
113                 if (ctx.pl310) {
114                         err = ctx.pl310->enable();
115                         if (err) {
116                                 pr_err("error: pl310 enable\n");
117                                 goto errout_preempt;
118                         }
119                 }
120
121                 ctx.comm->reset();
122
123                 err = quadd_hrt_start();
124                 if (err) {
125                         pr_err("error: hrt start\n");
126                         goto errout_preempt;
127                 }
128
129                 preempt_enable();
130
131                 err = quadd_power_clk_start();
132                 if (err < 0) {
133                         pr_err("error: power_clk start\n");
134                         goto errout;
135                 }
136         }
137
138         return 0;
139
140 errout_preempt:
141         preempt_enable();
142
143 errout:
144         atomic_set(&ctx.started, 0);
145         tegra_profiler_unlock();
146
147         return err;
148 }
149
150 static void stop(void)
151 {
152         if (atomic_cmpxchg(&ctx.started, 1, 0)) {
153                 preempt_disable();
154
155                 quadd_hrt_stop();
156
157                 ctx.comm->reset();
158
159                 quadd_unwind_stop();
160
161                 if (ctx.pmu)
162                         ctx.pmu->disable();
163
164                 if (ctx.pl310)
165                         ctx.pl310->disable();
166
167                 tegra_profiler_unlock();
168
169                 preempt_enable();
170
171                 quadd_power_clk_stop();
172         }
173 }
174
175 static inline int
176 is_event_supported(struct source_info *si, const struct quadd_event *event)
177 {
178         unsigned int type, id;
179         int i, nr = si->nr_supp_events;
180         struct quadd_event *events = si->supp_events;
181
182         type = event->type;
183         id = event->id;
184
185         if (type == QUADD_EVENT_TYPE_RAW)
186                 return (id & ~si->raw_event_mask) == 0;
187
188         if (type == QUADD_EVENT_TYPE_HARDWARE) {
189                 for (i = 0; i < nr; i++) {
190                         if (id == events[i].id)
191                                 return 1;
192                 }
193         }
194
195         return 0;
196 }
197
198 static int
199 validate_freq(unsigned int freq)
200 {
201         return freq >= 100 && freq <= 100000;
202 }
203
204 static int
205 set_parameters_for_cpu(struct quadd_pmu_setup_for_cpu *params)
206 {
207         int i, err, nr_pmu = 0;
208         int cpuid = params->cpuid;
209
210         struct source_info *pmu_info = &per_cpu(ctx_pmu_info, cpuid);
211         struct quadd_event pmu_events[QUADD_MAX_COUNTERS];
212
213         if (!pmu_info->is_present)
214                 return -ENODEV;
215
216         if (pmu_info->nr_supp_events == 0)
217                 return -ENODEV;
218
219         for (i = 0; i < params->nr_events; i++) {
220                 struct quadd_event *event = &params->events[i];
221
222                 if (is_event_supported(pmu_info, event)) {
223                         pmu_events[nr_pmu++] = *event;
224                         pr_info("[%d] PMU active event: %#x (%s)\n",
225                                 cpuid, event->id,
226                                 event->type == QUADD_EVENT_TYPE_RAW ?
227                                 "raw" : "hw");
228                 } else {
229                         pr_err("[%d] Bad event: %#x (%s)\n", cpuid, event->id,
230                                event->type == QUADD_EVENT_TYPE_RAW ?
231                                "raw" : "hw");
232                         return -EINVAL;
233                 }
234         }
235
236         err = ctx.pmu->set_events(cpuid, pmu_events, nr_pmu);
237         if (err) {
238                 pr_err("PMU set parameters: error\n");
239                 return err;
240         }
241         per_cpu(ctx_pmu_info, cpuid).active = 1;
242
243         return err;
244 }
245
246 static int
247 set_parameters(struct quadd_parameters *p)
248 {
249         int i, err, uid = 0;
250         uid_t task_uid, current_uid;
251         struct quadd_event *pl310_events;
252         int nr_pl310 = 0;
253         struct task_struct *task;
254         u64 *low_addr_p;
255
256         if (!validate_freq(p->freq)) {
257                 pr_err("error: incorrect frequency: %u\n", p->freq);
258                 return -EINVAL;
259         }
260
261         /* Currently only one process */
262         if (p->nr_pids != 1)
263                 return -EINVAL;
264
265         p->package_name[sizeof(p->package_name) - 1] = '\0';
266
267         ctx.param = *p;
268
269         rcu_read_lock();
270         task = pid_task(find_vpid(p->pids[0]), PIDTYPE_PID);
271         rcu_read_unlock();
272         if (!task) {
273                 pr_err("error: process not found: %u\n", p->pids[0]);
274                 return -ESRCH;
275         }
276
277         current_uid = __kuid_val(current_fsuid());
278         task_uid = __kuid_val(task_uid(task));
279         pr_info("owner/task uids: %u/%u\n", current_uid, task_uid);
280
281         if (!capable(CAP_SYS_ADMIN)) {
282                 if (current_uid != task_uid) {
283                         pr_info("package: %s\n", p->package_name);
284
285                         uid = quadd_auth_is_debuggable((char *)p->package_name);
286                         if (uid < 0) {
287                                 pr_err("error: tegra profiler security service\n");
288                                 return uid;
289                         } else if (uid == 0) {
290                                 pr_err("error: app is not debuggable\n");
291                                 return -EACCES;
292                         }
293                         pr_info("app is debuggable, uid: %u\n", uid);
294
295                         if (task_uid != uid) {
296                                 pr_err("error: uids are not matched\n");
297                                 return -EACCES;
298                         }
299                 }
300                 ctx.collect_kernel_ips = 0;
301         } else {
302                 ctx.collect_kernel_ips = 1;
303         }
304
305         for (i = 0; i < p->nr_events; i++) {
306                 unsigned int type, id;
307                 struct quadd_event *event = &p->events[i];
308
309                 type = event->type;
310                 id = event->id;
311
312                 if (type != QUADD_EVENT_TYPE_HARDWARE)
313                         return -EINVAL;
314
315                 if (ctx.pl310 &&
316                     ctx.pl310_info.nr_supp_events > 0 &&
317                     is_event_supported(&ctx.pl310_info, event)) {
318                         pl310_events = event;
319
320                         pr_info("PL310 active event: %s\n",
321                                 quadd_get_hw_event_str(id));
322
323                         if (nr_pl310++ > 1) {
324                                 pr_err("error: multiply pl310 events\n");
325                                 return -EINVAL;
326                         }
327                 } else {
328                         pr_err("Bad event: %s\n",
329                                quadd_get_hw_event_str(id));
330                         return -EINVAL;
331                 }
332         }
333
334         if (ctx.pl310) {
335                 int cpuid = 0; /* We don't need cpuid for pl310.  */
336
337                 if (nr_pl310 == 1) {
338                         err = ctx.pl310->set_events(cpuid, pl310_events, 1);
339                         if (err) {
340                                 pr_info("pl310 set_parameters: error\n");
341                                 return err;
342                         }
343                         ctx.pl310_info.active = 1;
344                 } else {
345                         ctx.pl310_info.active = 0;
346                         ctx.pl310->set_events(cpuid, NULL, 0);
347                 }
348         }
349
350         low_addr_p = (u64 *)&p->reserved[QUADD_PARAM_IDX_BT_LOWER_BOUND];
351         ctx.hrt->low_addr = (unsigned long)*low_addr_p;
352         pr_info("bt lower bound: %#lx\n", ctx.hrt->low_addr);
353
354         err = quadd_unwind_start(task);
355         if (err)
356                 return err;
357
358         pr_info("New parameters have been applied\n");
359
360         return 0;
361 }
362
363 static void
364 get_capabilities_for_cpu(int cpuid, struct quadd_comm_cap_for_cpu *cap)
365 {
366         int i, id;
367         struct quadd_events_cap *events_cap;
368         struct source_info *s = &per_cpu(ctx_pmu_info, cpuid);
369
370         if (!s->is_present)
371                 return;
372
373         cap->cpuid = cpuid;
374         cap->l2_cache = 0;
375         cap->l2_multiple_events = 0;
376
377         events_cap = &cap->events_cap;
378
379         events_cap->raw_event_mask = s->raw_event_mask;
380
381         events_cap->cpu_cycles = 0;
382         events_cap->l1_dcache_read_misses = 0;
383         events_cap->l1_dcache_write_misses = 0;
384         events_cap->l1_icache_misses = 0;
385
386         events_cap->instructions = 0;
387         events_cap->branch_instructions = 0;
388         events_cap->branch_misses = 0;
389         events_cap->bus_cycles = 0;
390
391         events_cap->l2_dcache_read_misses = 0;
392         events_cap->l2_dcache_write_misses = 0;
393         events_cap->l2_icache_misses = 0;
394
395         for (i = 0; i < s->nr_supp_events; i++) {
396                 struct quadd_event *event = &s->supp_events[i];
397
398                 id = event->id;
399
400                 if (id == QUADD_EVENT_HW_L2_DCACHE_READ_MISSES ||
401                     id == QUADD_EVENT_HW_L2_DCACHE_WRITE_MISSES ||
402                     id == QUADD_EVENT_HW_L2_ICACHE_MISSES) {
403                         cap->l2_cache = 1;
404                         cap->l2_multiple_events = 1;
405                 }
406
407                 switch (id) {
408                 case QUADD_EVENT_HW_CPU_CYCLES:
409                         events_cap->cpu_cycles = 1;
410                         break;
411                 case QUADD_EVENT_HW_INSTRUCTIONS:
412                         events_cap->instructions = 1;
413                         break;
414                 case QUADD_EVENT_HW_BRANCH_INSTRUCTIONS:
415                         events_cap->branch_instructions = 1;
416                         break;
417                 case QUADD_EVENT_HW_BRANCH_MISSES:
418                         events_cap->branch_misses = 1;
419                         break;
420                 case QUADD_EVENT_HW_BUS_CYCLES:
421                         events_cap->bus_cycles = 1;
422                         break;
423
424                 case QUADD_EVENT_HW_L1_DCACHE_READ_MISSES:
425                         events_cap->l1_dcache_read_misses = 1;
426                         break;
427                 case QUADD_EVENT_HW_L1_DCACHE_WRITE_MISSES:
428                         events_cap->l1_dcache_write_misses = 1;
429                         break;
430                 case QUADD_EVENT_HW_L1_ICACHE_MISSES:
431                         events_cap->l1_icache_misses = 1;
432                         break;
433
434                 case QUADD_EVENT_HW_L2_DCACHE_READ_MISSES:
435                         events_cap->l2_dcache_read_misses = 1;
436                         break;
437                 case QUADD_EVENT_HW_L2_DCACHE_WRITE_MISSES:
438                         events_cap->l2_dcache_write_misses = 1;
439                         break;
440                 case QUADD_EVENT_HW_L2_ICACHE_MISSES:
441                         events_cap->l2_icache_misses = 1;
442                         break;
443
444                 default:
445                         pr_err_once("%s: error: invalid event\n",
446                                                 __func__);
447                         return;
448                 }
449         }
450 }
451
452 static u32 get_possible_cpu(void)
453 {
454         int cpu;
455         u32 mask = 0;
456         struct source_info *s;
457
458         if (ctx.pmu) {
459                 for_each_possible_cpu(cpu) {
460                         /* since we don't support more than 32 CPUs */
461                         if (cpu >= BITS_PER_BYTE * sizeof(mask))
462                                 break;
463
464                         s = &per_cpu(ctx_pmu_info, cpu);
465                         if (s->is_present)
466                                 mask |= (1U << cpu);
467                 }
468         }
469
470         return mask;
471 }
472
473 static void
474 get_capabilities(struct quadd_comm_cap *cap)
475 {
476         int i;
477         unsigned int extra = 0;
478         struct quadd_events_cap *events_cap = &cap->events_cap;
479
480         cap->pmu = ctx.pmu ? 1 : 0;
481
482         cap->l2_cache = 0;
483         if (ctx.pl310) {
484                 cap->l2_cache = 1;
485                 cap->l2_multiple_events = 0;
486         }
487
488         events_cap->cpu_cycles = 0;
489         events_cap->l1_dcache_read_misses = 0;
490         events_cap->l1_dcache_write_misses = 0;
491         events_cap->l1_icache_misses = 0;
492
493         events_cap->instructions = 0;
494         events_cap->branch_instructions = 0;
495         events_cap->branch_misses = 0;
496         events_cap->bus_cycles = 0;
497
498         events_cap->l2_dcache_read_misses = 0;
499         events_cap->l2_dcache_write_misses = 0;
500         events_cap->l2_icache_misses = 0;
501
502         if (ctx.pl310) {
503                 unsigned int type, id;
504                 struct source_info *s = &ctx.pl310_info;
505
506                 for (i = 0; i < s->nr_supp_events; i++) {
507                         struct quadd_event *event = &s->supp_events[i];
508
509                         type = event->type;
510                         id = event->id;
511
512                         switch (id) {
513                         case QUADD_EVENT_HW_L2_DCACHE_READ_MISSES:
514                                 events_cap->l2_dcache_read_misses = 1;
515                                 break;
516                         case QUADD_EVENT_HW_L2_DCACHE_WRITE_MISSES:
517                                 events_cap->l2_dcache_write_misses = 1;
518                                 break;
519                         case QUADD_EVENT_HW_L2_ICACHE_MISSES:
520                                 events_cap->l2_icache_misses = 1;
521                                 break;
522
523                         default:
524                                 pr_err_once("%s: error: invalid event\n",
525                                             __func__);
526                                 return;
527                         }
528                 }
529         }
530
531         cap->tegra_lp_cluster = quadd_is_cpu_with_lp_cluster();
532         cap->power_rate = 1;
533         cap->blocked_read = 1;
534
535         extra |= QUADD_COMM_CAP_EXTRA_BT_KERNEL_CTX;
536         extra |= QUADD_COMM_CAP_EXTRA_GET_MMAP;
537         extra |= QUADD_COMM_CAP_EXTRA_GROUP_SAMPLES;
538         extra |= QUADD_COMM_CAP_EXTRA_BT_UNWIND_TABLES;
539         extra |= QUADD_COMM_CAP_EXTRA_SUPPORT_AARCH64;
540         extra |= QUADD_COMM_CAP_EXTRA_SPECIAL_ARCH_MMAP;
541         extra |= QUADD_COMM_CAP_EXTRA_UNWIND_MIXED;
542         extra |= QUADD_COMM_CAP_EXTRA_UNW_ENTRY_TYPE;
543         extra |= QUADD_COMM_CAP_EXTRA_RB_MMAP_OP;
544         extra |= QUADD_COMM_CAP_EXTRA_CPU_MASK;
545
546         if (ctx.hrt->tc)
547                 extra |= QUADD_COMM_CAP_EXTRA_ARCH_TIMER;
548
549         cap->reserved[QUADD_COMM_CAP_IDX_EXTRA] = extra;
550         cap->reserved[QUADD_COMM_CAP_IDX_CPU_MASK] = get_possible_cpu();
551 }
552
553 void quadd_get_state(struct quadd_module_state *state)
554 {
555         unsigned int status = 0;
556
557         quadd_hrt_get_state(state);
558
559         if (ctx.comm->is_active())
560                 status |= QUADD_MOD_STATE_STATUS_IS_ACTIVE;
561
562         if (quadd_auth_is_auth_open())
563                 status |= QUADD_MOD_STATE_STATUS_IS_AUTH_OPEN;
564
565         state->reserved[QUADD_MOD_STATE_IDX_STATUS] = status;
566 }
567
568 static int
569 set_extab(struct quadd_sections *extabs,
570           struct quadd_mmap_area *mmap)
571 {
572         return quadd_unwind_set_extab(extabs, mmap);
573 }
574
575 static void
576 delete_mmap(struct quadd_mmap_area *mmap)
577 {
578         quadd_unwind_delete_mmap(mmap);
579 }
580
581 static int
582 is_cpu_present(int cpuid)
583 {
584         struct source_info *s = &per_cpu(ctx_pmu_info, cpuid);
585
586         return s->is_present;
587 }
588
589 static struct quadd_comm_control_interface control = {
590         .start                  = start,
591         .stop                   = stop,
592         .set_parameters         = set_parameters,
593         .set_parameters_for_cpu = set_parameters_for_cpu,
594         .get_capabilities       = get_capabilities,
595         .get_capabilities_for_cpu = get_capabilities_for_cpu,
596         .get_state              = quadd_get_state,
597         .set_extab              = set_extab,
598         .delete_mmap            = delete_mmap,
599         .is_cpu_present         = is_cpu_present,
600 };
601
602 static int __init quadd_module_init(void)
603 {
604         int i, nr_events, err;
605         unsigned int raw_event_mask;
606         struct quadd_event *events;
607         int cpuid;
608
609         pr_info("Branch: %s\n", QUADD_MODULE_BRANCH);
610         pr_info("Version: %s\n", QUADD_MODULE_VERSION);
611         pr_info("Samples version: %d\n", QUADD_SAMPLES_VERSION);
612         pr_info("IO version: %d\n", QUADD_IO_VERSION);
613
614 #ifdef QM_DEBUG_SAMPLES_ENABLE
615         pr_info("############## DEBUG VERSION! ##############\n");
616 #endif
617
618         atomic_set(&ctx.started, 0);
619         atomic_set(&ctx.tegra_profiler_lock, 0);
620
621         get_default_properties();
622
623         for_each_possible_cpu(cpuid) {
624                 struct source_info *pmu_info = &per_cpu(ctx_pmu_info, cpuid);
625
626                 pmu_info->active = 0;
627                 pmu_info->is_present = 0;
628         }
629
630         ctx.pl310_info.active = 0;
631
632 #ifdef CONFIG_ARM64
633         ctx.pmu = quadd_armv8_pmu_init();
634 #else
635         ctx.pmu = quadd_armv7_pmu_init();
636 #endif
637         if (!ctx.pmu) {
638                 pr_err("PMU init failed\n");
639                 return -ENODEV;
640         }
641
642         for_each_possible_cpu(cpuid) {
643                 struct quadd_arch_info *arch;
644                 struct source_info *pmu_info;
645
646                 arch = ctx.pmu->get_arch(cpuid);
647                 if (!arch)
648                         continue;
649
650                 pmu_info = &per_cpu(ctx_pmu_info, cpuid);
651                 pmu_info->is_present = 1;
652
653                 events = pmu_info->supp_events;
654                 nr_events =
655                     ctx.pmu->get_supported_events(cpuid, events,
656                                                   QUADD_MAX_COUNTERS,
657                                                   &raw_event_mask);
658
659                 pmu_info->nr_supp_events = nr_events;
660                 pmu_info->raw_event_mask = raw_event_mask;
661
662                 pr_debug("CPU: %d PMU: amount of events: %d, raw mask: %#x\n",
663                          cpuid, nr_events, raw_event_mask);
664
665                 for (i = 0; i < nr_events; i++)
666                         pr_debug("CPU: %d PMU event: %s\n", cpuid,
667                                  quadd_get_hw_event_str(events[i].id));
668         }
669
670 #ifdef CONFIG_CACHE_L2X0
671         ctx.pl310 = quadd_l2x0_events_init();
672 #else
673         ctx.pl310 = NULL;
674 #endif
675         if (ctx.pl310) {
676                 events = ctx.pl310_info.supp_events;
677                 nr_events = ctx.pl310->get_supported_events(0, events,
678                                                             QUADD_MAX_COUNTERS,
679                                                             &raw_event_mask);
680                 ctx.pl310_info.nr_supp_events = nr_events;
681
682                 pr_info("pl310 success, amount of events: %d\n",
683                         nr_events);
684
685                 for (i = 0; i < nr_events; i++)
686                         pr_info("pl310 event: %s\n",
687                                 quadd_get_hw_event_str(events[i].id));
688         } else {
689                 pr_debug("PL310 not found\n");
690         }
691
692         ctx.hrt = quadd_hrt_init(&ctx);
693         if (IS_ERR(ctx.hrt)) {
694                 pr_err("error: HRT init failed\n");
695                 return PTR_ERR(ctx.hrt);
696         }
697
698         err = quadd_power_clk_init(&ctx);
699         if (err < 0) {
700                 pr_err("error: POWER CLK init failed\n");
701                 return err;
702         }
703
704         ctx.comm = quadd_comm_events_init(&control);
705         if (IS_ERR(ctx.comm)) {
706                 pr_err("error: COMM init failed\n");
707                 return PTR_ERR(ctx.comm);
708         }
709
710         err = quadd_auth_init(&ctx);
711         if (err < 0) {
712                 pr_err("error: auth failed\n");
713                 return err;
714         }
715
716         err = quadd_unwind_init();
717         if (err < 0) {
718                 pr_err("error: EH unwinding init failed\n");
719                 return err;
720         }
721
722         get_capabilities(&ctx.cap);
723
724         for_each_possible_cpu(cpuid)
725                 get_capabilities_for_cpu(cpuid, &per_cpu(per_cpu_caps, cpuid));
726
727         quadd_proc_init(&ctx);
728
729         return 0;
730 }
731
732 static void __exit quadd_module_exit(void)
733 {
734         pr_info("QuadD module exit\n");
735
736         quadd_hrt_deinit();
737         quadd_power_clk_deinit();
738         quadd_comm_events_exit();
739         quadd_auth_deinit();
740         quadd_proc_deinit();
741         quadd_unwind_deinit();
742
743 #ifdef CONFIG_ARM64
744         quadd_armv8_pmu_deinit();
745 #else
746         quadd_armv7_pmu_deinit();
747 #endif
748 }
749
750 module_init(quadd_module_init);
751 module_exit(quadd_module_exit);
752
753 MODULE_LICENSE("GPL");
754
755 MODULE_AUTHOR("Nvidia Ltd");
756 MODULE_DESCRIPTION("Tegra profiler");