]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/blob - drivers/misc/tegra-profiler/hrt.c
misc: tegra-profiler: add unwind entry checking
[sojka/nv-tegra/linux-3.10.git] / drivers / misc / tegra-profiler / hrt.c
1 /*
2  * drivers/misc/tegra-profiler/hrt.c
3  *
4  * Copyright (c) 2015, 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/sched.h>
20 #include <linux/hrtimer.h>
21 #include <linux/slab.h>
22 #include <linux/cpu.h>
23 #include <linux/ptrace.h>
24 #include <linux/interrupt.h>
25 #include <linux/err.h>
26 #include <linux/nsproxy.h>
27 #include <clocksource/arm_arch_timer.h>
28
29 #include <asm/cputype.h>
30 #include <asm/irq_regs.h>
31 #include <asm/arch_timer.h>
32
33 #include <linux/tegra_profiler.h>
34
35 #include "quadd.h"
36 #include "hrt.h"
37 #include "comm.h"
38 #include "mmap.h"
39 #include "ma.h"
40 #include "power_clk.h"
41 #include "tegra.h"
42 #include "debug.h"
43
44 static struct quadd_hrt_ctx hrt;
45
46 static void
47 read_all_sources(struct pt_regs *regs, struct task_struct *task);
48
49 struct hrt_event_value {
50         int event_id;
51         u32 value;
52 };
53
54 static inline u32 get_task_state(struct task_struct *task)
55 {
56         return (u32)(task->state | task->exit_state);
57 }
58
59 static enum hrtimer_restart hrtimer_handler(struct hrtimer *hrtimer)
60 {
61         struct pt_regs *regs;
62
63         regs = get_irq_regs();
64
65         if (!atomic_read(&hrt.active))
66                 return HRTIMER_NORESTART;
67
68         qm_debug_handler_sample(regs);
69
70         if (regs)
71                 read_all_sources(regs, NULL);
72
73         hrtimer_forward_now(hrtimer, ns_to_ktime(hrt.sample_period));
74         qm_debug_timer_forward(regs, hrt.sample_period);
75
76         return HRTIMER_RESTART;
77 }
78
79 static void start_hrtimer(struct quadd_cpu_context *cpu_ctx)
80 {
81         u64 period = hrt.sample_period;
82
83         __hrtimer_start_range_ns(&cpu_ctx->hrtimer,
84                                  ns_to_ktime(period), 0,
85                                  HRTIMER_MODE_REL_PINNED, 0);
86         qm_debug_timer_start(NULL, period);
87 }
88
89 static void cancel_hrtimer(struct quadd_cpu_context *cpu_ctx)
90 {
91         hrtimer_cancel(&cpu_ctx->hrtimer);
92         qm_debug_timer_cancel();
93 }
94
95 static void init_hrtimer(struct quadd_cpu_context *cpu_ctx)
96 {
97         hrtimer_init(&cpu_ctx->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
98         cpu_ctx->hrtimer.function = hrtimer_handler;
99 }
100
101 static inline u64 get_posix_clock_monotonic_time(void)
102 {
103         struct timespec ts;
104
105         do_posix_clock_monotonic_gettime(&ts);
106         return timespec_to_ns(&ts);
107 }
108
109 static inline u64 get_arch_time(struct timecounter *tc)
110 {
111         cycle_t value;
112         const struct cyclecounter *cc = tc->cc;
113
114         value = cc->read(cc);
115         return cyclecounter_cyc2ns(cc, value);
116 }
117
118 u64 quadd_get_time(void)
119 {
120         struct timecounter *tc = hrt.tc;
121
122         return (tc && hrt.use_arch_timer) ?
123                 get_arch_time(tc) :
124                 get_posix_clock_monotonic_time();
125 }
126
127 static void
128 __put_sample(struct quadd_record_data *data,
129              struct quadd_iovec *vec,
130              int vec_count, int cpu_id)
131 {
132         ssize_t err;
133         struct quadd_comm_data_interface *comm = hrt.quadd_ctx->comm;
134
135         err = comm->put_sample(data, vec, vec_count, cpu_id);
136         if (err < 0)
137                 atomic64_inc(&hrt.skipped_samples);
138
139         atomic64_inc(&hrt.counter_samples);
140 }
141
142 void
143 quadd_put_sample_this_cpu(struct quadd_record_data *data,
144                           struct quadd_iovec *vec, int vec_count)
145 {
146         __put_sample(data, vec, vec_count, -1);
147 }
148
149 void
150 quadd_put_sample(struct quadd_record_data *data,
151                  struct quadd_iovec *vec, int vec_count)
152 {
153         __put_sample(data, vec, vec_count, 0);
154 }
155
156 static void put_header(void)
157 {
158         int cpu_id;
159         int nr_events = 0, max_events = QUADD_MAX_COUNTERS;
160         int events[QUADD_MAX_COUNTERS];
161         struct quadd_record_data record;
162         struct quadd_header_data *hdr = &record.hdr;
163         struct quadd_parameters *param = &hrt.quadd_ctx->param;
164         unsigned int extra = param->reserved[QUADD_PARAM_IDX_EXTRA];
165         struct quadd_iovec vec;
166         struct quadd_ctx *ctx = hrt.quadd_ctx;
167         struct quadd_event_source_interface *pmu = ctx->pmu;
168         struct quadd_event_source_interface *pl310 = ctx->pl310;
169
170         record.record_type = QUADD_RECORD_TYPE_HEADER;
171
172         hdr->magic = QUADD_HEADER_MAGIC;
173         hdr->version = QUADD_SAMPLES_VERSION;
174
175         hdr->backtrace = param->backtrace;
176         hdr->use_freq = param->use_freq;
177         hdr->system_wide = param->system_wide;
178
179         /* TODO: dynamically */
180 #ifdef QM_DEBUG_SAMPLES_ENABLE
181         hdr->debug_samples = 1;
182 #else
183         hdr->debug_samples = 0;
184 #endif
185
186         hdr->freq = param->freq;
187         hdr->ma_freq = param->ma_freq;
188         hdr->power_rate_freq = param->power_rate_freq;
189
190         hdr->power_rate = hdr->power_rate_freq > 0 ? 1 : 0;
191         hdr->get_mmap = (extra & QUADD_PARAM_EXTRA_GET_MMAP) ? 1 : 0;
192
193         hdr->reserved = 0;
194         hdr->extra_length = 0;
195
196         if (hdr->backtrace) {
197                 struct quadd_unw_methods *um = &hrt.um;
198
199                 hdr->reserved |= um->fp ? QUADD_HDR_BT_FP : 0;
200                 hdr->reserved |= um->ut ? QUADD_HDR_BT_UT : 0;
201                 hdr->reserved |= um->ut_ce ? QUADD_HDR_BT_UT_CE : 0;
202                 hdr->reserved |= um->dwarf ? QUADD_HDR_BT_DWARF : 0;
203         }
204
205         if (hrt.use_arch_timer)
206                 hdr->reserved |= QUADD_HDR_USE_ARCH_TIMER;
207
208         if (hrt.get_stack_offset)
209                 hdr->reserved |= QUADD_HDR_STACK_OFFSET;
210
211         if (pmu)
212                 nr_events += pmu->get_current_events(events, max_events);
213
214         if (pl310)
215                 nr_events += pl310->get_current_events(events + nr_events,
216                                                        max_events - nr_events);
217
218         hdr->nr_events = nr_events;
219
220         vec.base = events;
221         vec.len = nr_events * sizeof(events[0]);
222
223         for_each_possible_cpu(cpu_id)
224                 __put_sample(&record, &vec, 1, cpu_id);
225 }
226
227 static void
228 put_sched_sample(struct task_struct *task, int is_sched_in)
229 {
230         unsigned int cpu, flags;
231         struct quadd_record_data record;
232         struct quadd_sched_data *s = &record.sched;
233
234         record.record_type = QUADD_RECORD_TYPE_SCHED;
235
236         cpu = quadd_get_processor_id(NULL, &flags);
237         s->cpu = cpu;
238         s->lp_mode = (flags & QUADD_CPUMODE_TEGRA_POWER_CLUSTER_LP) ? 1 : 0;
239
240         s->sched_in = is_sched_in ? 1 : 0;
241         s->time = quadd_get_time();
242         s->pid = task->pid;
243
244         s->reserved = 0;
245
246         s->data[QUADD_SCHED_IDX_TASK_STATE] = get_task_state(task);
247         s->data[QUADD_SCHED_IDX_RESERVED] = 0;
248
249         quadd_put_sample_this_cpu(&record, NULL, 0);
250 }
251
252 static int get_sample_data(struct quadd_sample_data *sample,
253                            struct pt_regs *regs,
254                            struct task_struct *task)
255 {
256         unsigned int cpu, flags;
257         struct quadd_ctx *quadd_ctx = hrt.quadd_ctx;
258
259         cpu = quadd_get_processor_id(regs, &flags);
260         sample->cpu = cpu;
261
262         sample->lp_mode =
263                 (flags & QUADD_CPUMODE_TEGRA_POWER_CLUSTER_LP) ? 1 : 0;
264         sample->thumb_mode = (flags & QUADD_CPUMODE_THUMB) ? 1 : 0;
265         sample->user_mode = user_mode(regs) ? 1 : 0;
266
267         /* For security reasons, hide IPs from the kernel space. */
268         if (!sample->user_mode && !quadd_ctx->collect_kernel_ips)
269                 sample->ip = 0;
270         else
271                 sample->ip = instruction_pointer(regs);
272
273         sample->time = quadd_get_time();
274         sample->reserved = 0;
275         sample->pid = task->pid;
276         sample->in_interrupt = in_interrupt() ? 1 : 0;
277
278         return 0;
279 }
280
281 static int read_source(struct quadd_event_source_interface *source,
282                        struct pt_regs *regs,
283                        struct hrt_event_value *events_vals,
284                        int max_events)
285 {
286         int nr_events, i;
287         u32 prev_val, val, res_val;
288         struct event_data events[QUADD_MAX_COUNTERS];
289
290         if (!source)
291                 return 0;
292
293         max_events = min_t(int, max_events, QUADD_MAX_COUNTERS);
294         nr_events = source->read(events, max_events);
295
296         for (i = 0; i < nr_events; i++) {
297                 struct event_data *s = &events[i];
298
299                 prev_val = s->prev_val;
300                 val = s->val;
301
302                 if (prev_val <= val)
303                         res_val = val - prev_val;
304                 else
305                         res_val = QUADD_U32_MAX - prev_val + val;
306
307                 if (s->event_source == QUADD_EVENT_SOURCE_PL310) {
308                         int nr_active = atomic_read(&hrt.nr_active_all_core);
309                         if (nr_active > 1)
310                                 res_val /= nr_active;
311                 }
312
313                 events_vals[i].event_id = s->event_id;
314                 events_vals[i].value = res_val;
315         }
316
317         return nr_events;
318 }
319
320 static long
321 get_stack_offset(struct task_struct *task,
322                  struct pt_regs *regs,
323                  struct quadd_callchain *cc)
324 {
325         unsigned long sp;
326         struct vm_area_struct *vma;
327         struct mm_struct *mm = task->mm;
328
329         if (!regs || !mm)
330                 return -ENOMEM;
331
332         sp = cc->nr > 0 ? cc->curr_sp :
333                 quadd_user_stack_pointer(regs);
334
335         vma = find_vma(mm, sp);
336         if (!vma)
337                 return -ENOMEM;
338
339         return vma->vm_end - sp;
340 }
341
342 static void
343 read_all_sources(struct pt_regs *regs, struct task_struct *task)
344 {
345         u32 state, extra_data = 0, urcs = 0;
346         int i, vec_idx = 0, bt_size = 0;
347         int nr_events = 0, nr_positive_events = 0;
348         struct pt_regs *user_regs;
349         struct quadd_iovec vec[6];
350         struct hrt_event_value events[QUADD_MAX_COUNTERS];
351         u32 events_extra[QUADD_MAX_COUNTERS];
352
353         struct quadd_record_data record_data;
354         struct quadd_sample_data *s = &record_data.sample;
355
356         struct quadd_ctx *ctx = hrt.quadd_ctx;
357         struct quadd_cpu_context *cpu_ctx = this_cpu_ptr(hrt.cpu_ctx);
358         struct quadd_callchain *cc = &cpu_ctx->cc;
359
360         if (!regs)
361                 return;
362
363         if (atomic_read(&cpu_ctx->nr_active) == 0)
364                 return;
365
366         if (!task)
367                 task = current;
368
369         if (task_is_dead(task))
370                 return;
371
372         rcu_read_lock();
373         if (!task_nsproxy(task)) {
374                 rcu_read_unlock();
375                 return;
376         }
377         rcu_read_unlock();
378
379         if (ctx->pmu && ctx->pmu_info.active)
380                 nr_events += read_source(ctx->pmu, regs,
381                                          events, QUADD_MAX_COUNTERS);
382
383         if (ctx->pl310 && ctx->pl310_info.active)
384                 nr_events += read_source(ctx->pl310, regs,
385                                          events + nr_events,
386                                          QUADD_MAX_COUNTERS - nr_events);
387
388         if (!nr_events)
389                 return;
390
391         if (user_mode(regs))
392                 user_regs = regs;
393         else
394                 user_regs = current_pt_regs();
395
396         if (get_sample_data(s, regs, task))
397                 return;
398
399         vec[vec_idx].base = &extra_data;
400         vec[vec_idx].len = sizeof(extra_data);
401         vec_idx++;
402
403         s->reserved = 0;
404
405         cc->nr = 0;
406         cc->curr_sp = 0;
407         cc->curr_fp = 0;
408         cc->curr_pc = 0;
409         cc->curr_lr = 0;
410
411         if (ctx->param.backtrace) {
412                 cc->um = hrt.um;
413
414                 bt_size = quadd_get_user_callchain(user_regs, cc, ctx, task);
415
416                 if (!bt_size && !user_mode(regs)) {
417                         unsigned long pc = instruction_pointer(user_regs);
418
419                         cc->nr = 0;
420 #ifdef CONFIG_ARM64
421                         cc->cs_64 = compat_user_mode(user_regs) ? 0 : 1;
422 #else
423                         cc->cs_64 = 0;
424 #endif
425                         bt_size += quadd_callchain_store(cc, pc,
426                                                          QUADD_UNW_TYPE_KCTX);
427                 }
428
429                 if (bt_size > 0) {
430                         int ip_size = cc->cs_64 ? sizeof(u64) : sizeof(u32);
431                         int nr_types = DIV_ROUND_UP(bt_size, 8);
432
433                         vec[vec_idx].base = cc->cs_64 ?
434                                 (void *)cc->ip_64 : (void *)cc->ip_32;
435                         vec[vec_idx].len = bt_size * ip_size;
436                         vec_idx++;
437
438                         vec[vec_idx].base = cc->types;
439                         vec[vec_idx].len = nr_types * sizeof(cc->types[0]);
440                         vec_idx++;
441
442                         if (cc->cs_64)
443                                 extra_data |= QUADD_SED_IP64;
444                 }
445
446                 urcs |= (cc->urc_fp & QUADD_SAMPLE_URC_MASK) <<
447                         QUADD_SAMPLE_URC_SHIFT_FP;
448                 urcs |= (cc->urc_ut & QUADD_SAMPLE_URC_MASK) <<
449                         QUADD_SAMPLE_URC_SHIFT_UT;
450                 urcs |= (cc->urc_dwarf & QUADD_SAMPLE_URC_MASK) <<
451                         QUADD_SAMPLE_URC_SHIFT_DWARF;
452
453                 s->reserved |= QUADD_SAMPLE_RES_URCS_ENABLED;
454
455                 vec[vec_idx].base = &urcs;
456                 vec[vec_idx].len = sizeof(urcs);
457                 vec_idx++;
458         }
459         s->callchain_nr = bt_size;
460
461         if (hrt.get_stack_offset) {
462                 long offset = get_stack_offset(task, user_regs, cc);
463                 if (offset > 0) {
464                         u32 off = offset >> 2;
465                         off = min_t(u32, off, 0xffff);
466                         extra_data |= off << QUADD_SED_STACK_OFFSET_SHIFT;
467                 }
468         }
469
470         record_data.record_type = QUADD_RECORD_TYPE_SAMPLE;
471
472         s->events_flags = 0;
473         for (i = 0; i < nr_events; i++) {
474                 u32 value = events[i].value;
475                 if (value > 0) {
476                         s->events_flags |= 1 << i;
477                         events_extra[nr_positive_events++] = value;
478                 }
479         }
480
481         if (nr_positive_events == 0)
482                 return;
483
484         vec[vec_idx].base = events_extra;
485         vec[vec_idx].len = nr_positive_events * sizeof(events_extra[0]);
486         vec_idx++;
487
488         state = get_task_state(task);
489         if (state) {
490                 s->state = 1;
491                 vec[vec_idx].base = &state;
492                 vec[vec_idx].len = sizeof(state);
493                 vec_idx++;
494         } else {
495                 s->state = 0;
496         }
497
498         quadd_put_sample_this_cpu(&record_data, vec, vec_idx);
499 }
500
501 static inline int
502 is_profile_process(struct task_struct *task)
503 {
504         int i;
505         pid_t pid, profile_pid;
506         struct quadd_ctx *ctx = hrt.quadd_ctx;
507
508         if (!task)
509                 return 0;
510
511         pid = task->tgid;
512
513         for (i = 0; i < ctx->param.nr_pids; i++) {
514                 profile_pid = ctx->param.pids[i];
515                 if (profile_pid == pid)
516                         return 1;
517         }
518         return 0;
519 }
520
521 static int
522 add_active_thread(struct quadd_cpu_context *cpu_ctx, pid_t pid, pid_t tgid)
523 {
524         struct quadd_thread_data *t_data = &cpu_ctx->active_thread;
525
526         if (t_data->pid > 0 ||
527                 atomic_read(&cpu_ctx->nr_active) > 0) {
528                 pr_warn_once("Warning for thread: %d\n", (int)pid);
529                 return 0;
530         }
531
532         t_data->pid = pid;
533         t_data->tgid = tgid;
534         return 1;
535 }
536
537 static int remove_active_thread(struct quadd_cpu_context *cpu_ctx, pid_t pid)
538 {
539         struct quadd_thread_data *t_data = &cpu_ctx->active_thread;
540
541         if (t_data->pid < 0)
542                 return 0;
543
544         if (t_data->pid == pid) {
545                 t_data->pid = -1;
546                 t_data->tgid = -1;
547                 return 1;
548         }
549
550         pr_warn_once("Warning for thread: %d\n", (int)pid);
551         return 0;
552 }
553
554 void __quadd_task_sched_in(struct task_struct *prev,
555                            struct task_struct *task)
556 {
557         struct quadd_cpu_context *cpu_ctx = this_cpu_ptr(hrt.cpu_ctx);
558         struct quadd_ctx *ctx = hrt.quadd_ctx;
559         struct event_data events[QUADD_MAX_COUNTERS];
560         /* static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 2); */
561
562         if (likely(!atomic_read(&hrt.active)))
563                 return;
564 /*
565         if (__ratelimit(&ratelimit_state))
566                 pr_info("sch_in, cpu: %d, prev: %u (%u) \t--> curr: %u (%u)\n",
567                         smp_processor_id(), (unsigned int)prev->pid,
568                         (unsigned int)prev->tgid, (unsigned int)task->pid,
569                         (unsigned int)task->tgid);
570 */
571
572         if (is_profile_process(task)) {
573                 put_sched_sample(task, 1);
574
575                 add_active_thread(cpu_ctx, task->pid, task->tgid);
576                 atomic_inc(&cpu_ctx->nr_active);
577
578                 if (atomic_read(&cpu_ctx->nr_active) == 1) {
579                         if (ctx->pmu)
580                                 ctx->pmu->start();
581
582                         if (ctx->pl310)
583                                 ctx->pl310->read(events, 1);
584
585                         start_hrtimer(cpu_ctx);
586                         atomic_inc(&hrt.nr_active_all_core);
587                 }
588         }
589 }
590
591 void __quadd_task_sched_out(struct task_struct *prev,
592                             struct task_struct *next)
593 {
594         int n;
595         struct pt_regs *user_regs;
596         struct quadd_cpu_context *cpu_ctx = this_cpu_ptr(hrt.cpu_ctx);
597         struct quadd_ctx *ctx = hrt.quadd_ctx;
598         /* static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 2); */
599
600         if (likely(!atomic_read(&hrt.active)))
601                 return;
602 /*
603         if (__ratelimit(&ratelimit_state))
604                 pr_info("sch_out: cpu: %d, prev: %u (%u) \t--> next: %u (%u)\n",
605                         smp_processor_id(), (unsigned int)prev->pid,
606                         (unsigned int)prev->tgid, (unsigned int)next->pid,
607                         (unsigned int)next->tgid);
608 */
609
610         if (is_profile_process(prev)) {
611                 user_regs = task_pt_regs(prev);
612                 if (user_regs)
613                         read_all_sources(user_regs, prev);
614
615                 n = remove_active_thread(cpu_ctx, prev->pid);
616                 atomic_sub(n, &cpu_ctx->nr_active);
617
618                 if (n && atomic_read(&cpu_ctx->nr_active) == 0) {
619                         cancel_hrtimer(cpu_ctx);
620                         atomic_dec(&hrt.nr_active_all_core);
621
622                         if (ctx->pmu)
623                                 ctx->pmu->stop();
624                 }
625
626                 put_sched_sample(prev, 0);
627         }
628 }
629
630 void __quadd_event_mmap(struct vm_area_struct *vma)
631 {
632         struct quadd_parameters *param;
633
634         if (likely(!atomic_read(&hrt.active)))
635                 return;
636
637         if (!is_profile_process(current))
638                 return;
639
640         param = &hrt.quadd_ctx->param;
641         quadd_process_mmap(vma, param->pids[0]);
642 }
643
644 static void reset_cpu_ctx(void)
645 {
646         int cpu_id;
647         struct quadd_cpu_context *cpu_ctx;
648         struct quadd_thread_data *t_data;
649
650         for (cpu_id = 0; cpu_id < nr_cpu_ids; cpu_id++) {
651                 cpu_ctx = per_cpu_ptr(hrt.cpu_ctx, cpu_id);
652                 t_data = &cpu_ctx->active_thread;
653
654                 atomic_set(&cpu_ctx->nr_active, 0);
655
656                 t_data->pid = -1;
657                 t_data->tgid = -1;
658         }
659 }
660
661 int quadd_hrt_start(void)
662 {
663         int err;
664         u64 period;
665         long freq;
666         unsigned int extra;
667         struct quadd_ctx *ctx = hrt.quadd_ctx;
668         struct quadd_parameters *param = &ctx->param;
669
670         freq = ctx->param.freq;
671         freq = max_t(long, QUADD_HRT_MIN_FREQ, freq);
672         period = NSEC_PER_SEC / freq;
673         hrt.sample_period = period;
674
675         if (ctx->param.ma_freq > 0)
676                 hrt.ma_period = MSEC_PER_SEC / ctx->param.ma_freq;
677         else
678                 hrt.ma_period = 0;
679
680         atomic64_set(&hrt.counter_samples, 0);
681         atomic64_set(&hrt.skipped_samples, 0);
682
683         reset_cpu_ctx();
684
685         extra = param->reserved[QUADD_PARAM_IDX_EXTRA];
686
687         if (param->backtrace) {
688                 struct quadd_unw_methods *um = &hrt.um;
689
690                 um->fp = extra & QUADD_PARAM_EXTRA_BT_FP ? 1 : 0;
691                 um->ut = extra & QUADD_PARAM_EXTRA_BT_UT ? 1 : 0;
692                 um->ut_ce = extra & QUADD_PARAM_EXTRA_BT_UT_CE ? 1 : 0;
693                 um->dwarf = extra & QUADD_PARAM_EXTRA_BT_DWARF ? 1 : 0;
694
695                 pr_info("unw methods: fp/ut/ut_ce/dwarf: %u/%u/%u/%u\n",
696                         um->fp, um->ut, um->ut_ce, um->dwarf);
697         }
698
699         if (hrt.tc && (extra & QUADD_PARAM_EXTRA_USE_ARCH_TIMER))
700                 hrt.use_arch_timer = 1;
701         else
702                 hrt.use_arch_timer = 0;
703
704         pr_info("timer: %s\n", hrt.use_arch_timer ? "arch" : "monotonic clock");
705
706         hrt.get_stack_offset =
707                 (extra & QUADD_PARAM_EXTRA_STACK_OFFSET) ? 1 : 0;
708
709         put_header();
710
711         if (extra & QUADD_PARAM_EXTRA_GET_MMAP) {
712                 err = quadd_get_current_mmap(param->pids[0]);
713                 if (err) {
714                         pr_err("error: quadd_get_current_mmap\n");
715                         return err;
716                 }
717         }
718
719         if (ctx->pl310)
720                 ctx->pl310->start();
721
722         quadd_ma_start(&hrt);
723
724         atomic_set(&hrt.active, 1);
725
726         pr_info("Start hrt: freq/period: %ld/%llu\n", freq, period);
727         return 0;
728 }
729
730 void quadd_hrt_stop(void)
731 {
732         struct quadd_ctx *ctx = hrt.quadd_ctx;
733
734         pr_info("Stop hrt, samples all/skipped: %llu/%llu\n",
735                 atomic64_read(&hrt.counter_samples),
736                 atomic64_read(&hrt.skipped_samples));
737
738         if (ctx->pl310)
739                 ctx->pl310->stop();
740
741         quadd_ma_stop(&hrt);
742
743         atomic_set(&hrt.active, 0);
744
745         atomic64_set(&hrt.counter_samples, 0);
746         atomic64_set(&hrt.skipped_samples, 0);
747
748         /* reset_cpu_ctx(); */
749 }
750
751 void quadd_hrt_deinit(void)
752 {
753         if (atomic_read(&hrt.active))
754                 quadd_hrt_stop();
755
756         free_percpu(hrt.cpu_ctx);
757 }
758
759 void quadd_hrt_get_state(struct quadd_module_state *state)
760 {
761         state->nr_all_samples = atomic64_read(&hrt.counter_samples);
762         state->nr_skipped_samples = atomic64_read(&hrt.skipped_samples);
763 }
764
765 static void init_arch_timer(void)
766 {
767         u32 cntkctl = arch_timer_get_cntkctl();
768
769         if (cntkctl & ARCH_TIMER_USR_VCT_ACCESS_EN)
770                 hrt.tc = arch_timer_get_timecounter();
771         else
772                 hrt.tc = NULL;
773 }
774
775 struct quadd_hrt_ctx *quadd_hrt_init(struct quadd_ctx *ctx)
776 {
777         int cpu_id;
778         u64 period;
779         long freq;
780         struct quadd_cpu_context *cpu_ctx;
781
782         hrt.quadd_ctx = ctx;
783         atomic_set(&hrt.active, 0);
784
785         freq = ctx->param.freq;
786         freq = max_t(long, QUADD_HRT_MIN_FREQ, freq);
787         period = NSEC_PER_SEC / freq;
788         hrt.sample_period = period;
789
790         if (ctx->param.ma_freq > 0)
791                 hrt.ma_period = MSEC_PER_SEC / ctx->param.ma_freq;
792         else
793                 hrt.ma_period = 0;
794
795         atomic64_set(&hrt.counter_samples, 0);
796         init_arch_timer();
797
798         hrt.cpu_ctx = alloc_percpu(struct quadd_cpu_context);
799         if (!hrt.cpu_ctx)
800                 return ERR_PTR(-ENOMEM);
801
802         for_each_possible_cpu(cpu_id) {
803                 cpu_ctx = per_cpu_ptr(hrt.cpu_ctx, cpu_id);
804
805                 atomic_set(&cpu_ctx->nr_active, 0);
806
807                 cpu_ctx->active_thread.pid = -1;
808                 cpu_ctx->active_thread.tgid = -1;
809
810                 cpu_ctx->cc.hrt = &hrt;
811
812                 init_hrtimer(cpu_ctx);
813         }
814
815         return &hrt;
816 }