summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'driver/gator_main.c')
-rw-r--r--driver/gator_main.c1057
1 files changed, 1057 insertions, 0 deletions
diff --git a/driver/gator_main.c b/driver/gator_main.c
new file mode 100644
index 0000000..340756e
--- /dev/null
+++ b/driver/gator_main.c
@@ -0,0 +1,1057 @@
1/**
2 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10static unsigned long gator_protocol_version = 5;
11
12#include <linux/slab.h>
13#include <linux/cpu.h>
14#include <linux/sched.h>
15#include <linux/irq.h>
16#include <linux/vmalloc.h>
17#include <linux/hardirq.h>
18#include <linux/highmem.h>
19#include <linux/pagemap.h>
20#include <asm/uaccess.h>
21
22#include "gator.h"
23#include "gator_events.h"
24
25#ifndef CONFIG_GENERIC_TRACER
26#ifndef CONFIG_TRACING
27#error gator requires the kernel to have CONFIG_GENERIC_TRACER or CONFIG_TRACING defined
28#endif
29#endif
30
31#ifndef CONFIG_PROFILING
32#error gator requires the kernel to have CONFIG_PROFILING defined
33#endif
34
35#ifndef CONFIG_HIGH_RES_TIMERS
36#error gator requires the kernel to have CONFIG_HIGH_RES_TIMERS defined
37#endif
38
39#ifdef CONFIG_SMP
40#ifndef CONFIG_LOCAL_TIMERS
41#error gator requires the kernel to have CONFIG_LOCAL_TIMERS defined on SMP systems
42#endif
43#endif
44
45#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
46#error kernels prior to 2.6.32 are not supported
47#endif
48
49/******************************************************************************
50 * DEFINES
51 ******************************************************************************/
52#define BUFFER_SIZE_DEFAULT (256*1024)
53#define SYNC_FREQ_DEFAULT 1000
54
55#define NO_COOKIE 0UL
56#define INVALID_COOKIE ~0UL
57
58#define PROTOCOL_FRAME ~0
59#define PROTOCOL_START_TICK 1
60#define PROTOCOL_END_TICK 3
61#define PROTOCOL_START_BACKTRACE 5
62#define PROTOCOL_END_BACKTRACE 7
63#define PROTOCOL_COOKIE 9
64#define PROTOCOL_SCHEDULER_TRACE 11
65#define PROTOCOL_COUNTERS 13
66#define PROTOCOL_ANNOTATE 15
67#define PROTOCOL_CPU_SYNC 17
68
69#if defined(__arm__)
70#define PC_REG regs->ARM_pc
71#else
72#define PC_REG regs->ip
73#endif
74
75/******************************************************************************
76 * PER CPU
77 ******************************************************************************/
78static unsigned long gator_cpu_cores;
79static unsigned long gator_buffer_size;
80static unsigned long gator_backtrace_depth;
81
82static unsigned long gator_started;
83static unsigned long gator_buffer_opened;
84static unsigned long gator_timer_count;
85static unsigned long gator_streaming;
86static int gator_master_tick;
87static DEFINE_MUTEX(start_mutex);
88static DEFINE_MUTEX(gator_buffer_mutex);
89
90unsigned long gator_net_traffic;
91
92#define COMMIT_SIZE 128
93#define COMMIT_MASK (COMMIT_SIZE-1)
94static DEFINE_SPINLOCK(gator_commit_lock);
95static int *gator_commit;
96static int gator_commit_read;
97static int gator_commit_write;
98
99static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait);
100static DEFINE_PER_CPU(int, gator_cpu_sync);
101static DEFINE_PER_CPU(int, gator_cpu_tick);
102static DEFINE_PER_CPU(int, gator_first_time);
103
104/******************************************************************************
105 * Prototypes
106 ******************************************************************************/
107static void gator_buffer_write_packed_int(int cpu, unsigned int x);
108static void gator_buffer_write_string(int cpu, char *x);
109static int gator_write_packed_int(char *buffer, unsigned int x);
110static void gator_add_trace(int cpu, unsigned int address);
111static uint64_t gator_get_time(void);
112
113/******************************************************************************
114 * Application Includes
115 ******************************************************************************/
116#include "gator_cookies.c"
117#include "gator_trace_sched.c"
118#include "gator_backtrace.c"
119#include "gator_annotate.c"
120#include "gator_fs.c"
121
122/******************************************************************************
123 * Misc
124 ******************************************************************************/
125#if defined(__arm__)
126u32 gator_cpuid(void)
127{
128 u32 val;
129 asm volatile("mrc p15, 0, %0, c0, c0, 0" : "=r" (val));
130 return (val >> 4) & 0xfff;
131}
132#endif
133
134/******************************************************************************
135 * Commit interface
136 ******************************************************************************/
137static int buffer_commit_ready(void)
138{
139 return (gator_commit_read != gator_commit_write);
140}
141
142static void buffer_commit_read(int *cpu, int *readval, int *writeval)
143{
144 int read = gator_commit_read;
145 *cpu = gator_commit[read+0];
146 *readval = gator_commit[read+1];
147 *writeval = gator_commit[read+2];
148 gator_commit_read = (read + 4) & COMMIT_MASK;
149}
150
151static void buffer_commit_write(int cpu, int readval, int writeval) {
152 int write = gator_commit_write;
153 gator_commit[write+0] = cpu;
154 gator_commit[write+1] = readval;
155 gator_commit[write+2] = writeval;
156 gator_commit_write = (write + 4) & COMMIT_MASK;
157}
158
159/******************************************************************************
160 * Buffer management
161 ******************************************************************************/
162static uint32_t use_buffer_size;
163static uint32_t use_buffer_mask;
164static DEFINE_PER_CPU(int, use_buffer_seq);
165static DEFINE_PER_CPU(int, use_buffer_read);
166static DEFINE_PER_CPU(int, use_buffer_write);
167static DEFINE_PER_CPU(char *, use_buffer);
168
169static void gator_buffer_write_packed_int(int cpu, unsigned int x)
170{
171 uint32_t write = per_cpu(use_buffer_write, cpu);
172 uint32_t mask = use_buffer_mask;
173 char *buffer = per_cpu(use_buffer, cpu);
174 int write0 = (write + 0) & mask;
175 int write1 = (write + 1) & mask;
176 int write2 = (write + 2) & mask;
177 int write3 = (write + 3) & mask;
178 int write4 = (write + 4) & mask;
179 int write5 = (write + 5) & mask;
180
181 if ((x & 0xffffff80) == 0) {
182 buffer[write0] = x & 0x7f;
183 per_cpu(use_buffer_write, cpu) = write1;
184 } else if ((x & 0xffffc000) == 0) {
185 buffer[write0] = x | 0x80;
186 buffer[write1] = (x>>7) & 0x7f;
187 per_cpu(use_buffer_write, cpu) = write2;
188 } else if ((x & 0xffe00000) == 0) {
189 buffer[write0] = x | 0x80;
190 buffer[write1] = (x>>7) | 0x80;
191 buffer[write2] = (x>>14) & 0x7f;
192 per_cpu(use_buffer_write, cpu) = write3;
193 } else if ((x & 0xf0000000) == 0) {
194 buffer[write0] = x | 0x80;
195 buffer[write1] = (x>>7) | 0x80;
196 buffer[write2] = (x>>14) | 0x80;
197 buffer[write3] = (x>>21) & 0x7f;
198 per_cpu(use_buffer_write, cpu) = write4;
199 } else {
200 buffer[write0] = x | 0x80;
201 buffer[write1] = (x>>7) | 0x80;
202 buffer[write2] = (x>>14) | 0x80;
203 buffer[write3] = (x>>21) | 0x80;
204 buffer[write4] = (x>>28) & 0x0f;
205 per_cpu(use_buffer_write, cpu) = write5;
206 }
207}
208
209static int gator_write_packed_int(char *buffer, unsigned int x)
210{
211 if ((x & 0xffffff80) == 0) {
212 buffer[0] = x & 0x7f;
213 return 1;
214 } else if ((x & 0xffffc000) == 0) {
215 buffer[0] = x | 0x80;
216 buffer[1] = (x>>7) & 0x7f;
217 return 2;
218 } else if ((x & 0xffe00000) == 0) {
219 buffer[0] = x | 0x80;
220 buffer[1] = (x>>7) | 0x80;
221 buffer[2] = (x>>14) & 0x7f;
222 return 3;
223 } else if ((x & 0xf0000000) == 0) {
224 buffer[0] = x | 0x80;
225 buffer[1] = (x>>7) | 0x80;
226 buffer[2] = (x>>14) | 0x80;
227 buffer[3] = (x>>21) & 0x7f;
228 return 4;
229 } else {
230 buffer[0] = x | 0x80;
231 buffer[1] = (x>>7) | 0x80;
232 buffer[2] = (x>>14) | 0x80;
233 buffer[3] = (x>>21) | 0x80;
234 buffer[4] = (x>>28) & 0x0f;
235 return 5;
236 }
237}
238
239static void gator_buffer_write_bytes(int cpu, char *x, int len)
240{
241 uint32_t write = per_cpu(use_buffer_write, cpu);
242 uint32_t mask = use_buffer_mask;
243 char *buffer = per_cpu(use_buffer, cpu);
244 int i;
245
246 for (i = 0; i < len; i++) {
247 buffer[write] = x[i];
248 write = (write + 1) & mask;
249 }
250
251 per_cpu(use_buffer_write, cpu) = write;
252}
253
254static void gator_buffer_write_string(int cpu, char *x)
255{
256 int len = strlen(x);
257 gator_buffer_write_packed_int(cpu, len);
258 gator_buffer_write_bytes(cpu, x, len);
259}
260
261static void gator_buffer_header(int cpu)
262{
263 gator_buffer_write_packed_int(cpu, PROTOCOL_FRAME);
264 gator_buffer_write_packed_int(cpu, cpu);
265 gator_buffer_write_packed_int(cpu, per_cpu(use_buffer_seq, cpu));
266 per_cpu(use_buffer_seq, cpu)++;
267}
268
269static void gator_buffer_commit(int cpu)
270{
271 buffer_commit_write(cpu, per_cpu(use_buffer_read, cpu), per_cpu(use_buffer_write, cpu));
272 per_cpu(use_buffer_read, cpu) = per_cpu(use_buffer_write, cpu);
273 gator_buffer_header(cpu);
274 wake_up(&gator_buffer_wait);
275}
276
277static void gator_buffer_check(int cpu, int tick)
278{
279 if (!(tick % gator_timer_count)) {
280 int c, sync;
281 spin_lock(&gator_commit_lock);
282 // synchronize, if all online cpus have the same tick waypoint
283 sync = per_cpu(gator_cpu_sync, cpu) = per_cpu(gator_cpu_tick, cpu);
284 for_each_online_cpu(c) {
285 if (sync != per_cpu(gator_cpu_sync, c)) {
286 sync = 0;
287 break;
288 }
289 }
290 if (sync) {
291 gator_buffer_write_packed_int(cpu, PROTOCOL_CPU_SYNC);
292 }
293 gator_buffer_commit(cpu);
294 spin_unlock(&gator_commit_lock);
295 } else {
296 int available = per_cpu(use_buffer_write, cpu) - per_cpu(use_buffer_read, cpu);
297 if (available < 0) {
298 available += use_buffer_size;
299 }
300 if (available >= ((use_buffer_size * 3) / 4)) {
301 spin_lock(&gator_commit_lock);
302 gator_buffer_commit(cpu);
303 spin_unlock(&gator_commit_lock);
304 }
305 }
306}
307
308static void gator_add_trace(int cpu, unsigned int address)
309{
310 off_t offset = 0;
311 unsigned long cookie = get_address_cookie(cpu, current, address & ~1, &offset);
312
313 if (cookie == NO_COOKIE || cookie == INVALID_COOKIE) {
314 offset = address;
315 }
316
317 gator_buffer_write_packed_int(cpu, offset & ~1);
318 gator_buffer_write_packed_int(cpu, cookie);
319}
320
321static void gator_add_sample(int cpu, struct pt_regs * const regs)
322{
323 struct module *mod;
324 unsigned int addr, cookie = 0;
325 int inKernel = regs ? !user_mode(regs) : 1;
326 unsigned long exec_cookie = !inKernel ? get_exec_cookie(cpu, current) : NO_COOKIE;
327
328 gator_buffer_write_packed_int(cpu, PROTOCOL_START_BACKTRACE);
329
330 // TGID::PID::inKernel
331 gator_buffer_write_packed_int(cpu, exec_cookie);
332 gator_buffer_write_packed_int(cpu, (unsigned int)current->tgid);
333 gator_buffer_write_packed_int(cpu, (unsigned int)current->pid);
334 gator_buffer_write_packed_int(cpu, inKernel);
335
336 // get_irq_regs() will return NULL outside of IRQ context (e.g. nested IRQ)
337 if (regs) {
338 if (inKernel) {
339 addr = PC_REG;
340 mod = __module_address(addr);
341 if (mod) {
342 cookie = get_cookie(cpu, current, NULL, mod);
343 addr = addr - (unsigned long)mod->module_core;
344 }
345 gator_buffer_write_packed_int(cpu, addr & ~1);
346 gator_buffer_write_packed_int(cpu, cookie);
347 } else {
348 // Cookie+PC
349 gator_add_trace(cpu, PC_REG);
350
351 // Backtrace
352 if (gator_backtrace_depth)
353 arm_backtrace_eabi(cpu, regs, gator_backtrace_depth);
354 }
355 }
356
357 gator_buffer_write_packed_int(cpu, PROTOCOL_END_BACKTRACE);
358}
359
360static void gator_write_packet(int cpu, int type, int len, int *buffer)
361{
362 int i;
363 gator_buffer_write_packed_int(cpu, type);
364 gator_buffer_write_packed_int(cpu, len);
365 for (i = 0; i < len; i++) {
366 gator_buffer_write_packed_int(cpu, buffer[i]);
367 }
368}
369
370/******************************************************************************
371 * Interrupt Processing
372 ******************************************************************************/
373static LIST_HEAD(gator_events);
374
375static void gator_timer_interrupt(void)
376{
377 struct pt_regs * const regs = get_irq_regs();
378 int cpu = smp_processor_id();
379 int *buffer, len, tick;
380 struct gator_interface *gi;
381
382 // check full backtrace has enough space, otherwise may
383 // have breaks between samples in the same callstack
384 if (per_cpu(gator_first_time, cpu)) {
385 per_cpu(gator_first_time, cpu) = 0;
386
387 list_for_each_entry(gi, &gator_events, list)
388 if (gi->read)
389 gi->read(NULL);
390
391 return;
392 }
393
394 // Header
395 gator_buffer_write_packed_int(cpu, PROTOCOL_START_TICK); // Escape
396
397 // Output scheduler
398 len = gator_trace_sched_read(&buffer);
399 if (len > 0) {
400 gator_write_packet(cpu, PROTOCOL_SCHEDULER_TRACE, len, buffer);
401 }
402
403 // Output counters
404 list_for_each_entry(gi, &gator_events, list) {
405 if (gi->read) {
406 len = gi->read(&buffer);
407 if (len > 0)
408 gator_write_packet(cpu, PROTOCOL_COUNTERS, len, buffer);
409 }
410 }
411
412 // Output backtrace
413 gator_add_sample(cpu, regs);
414
415 // Timer Tick
416 tick = per_cpu(gator_cpu_tick, cpu);
417 if (tick == gator_master_tick) {
418 tick++;
419 per_cpu(gator_cpu_tick, cpu) = gator_master_tick = tick;
420 } else {
421 per_cpu(gator_cpu_tick, cpu) = tick = gator_master_tick;
422 }
423 gator_write_packet(cpu, PROTOCOL_END_TICK, 1, &tick);
424
425 // Check and commit; generally, commit is set to occur once per second
426 gator_buffer_check(cpu, tick);
427}
428
429/******************************************************************************
430 * hrtimer
431 ******************************************************************************/
432DEFINE_PER_CPU(struct hrtimer, percpu_hrtimer);
433DEFINE_PER_CPU(int, hrtimer_is_active);
434static int hrtimer_running;
435static ktime_t profiling_interval;
436
437static enum hrtimer_restart gator_hrtimer_notify(struct hrtimer *hrtimer)
438{
439 hrtimer_forward_now(hrtimer, profiling_interval);
440 gator_timer_interrupt();
441 return HRTIMER_RESTART;
442}
443
444static int gator_timer_init(void)
445{
446 return 0;
447}
448
449static void __gator_timer_offline(void *unused)
450{
451 int cpu = smp_processor_id();
452 if (per_cpu(hrtimer_is_active, cpu)) {
453 struct gator_interface *gi;
454 struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu);
455 hrtimer_cancel(hrtimer);
456 per_cpu(hrtimer_is_active, cpu) = 0;
457 gator_buffer_commit(cpu);
458
459 // offline any events
460 list_for_each_entry(gi, &gator_events, list)
461 if (gi->offline)
462 gi->offline();
463 }
464}
465
466static void gator_timer_offline(void)
467{
468 if (hrtimer_running) {
469 hrtimer_running = 0;
470
471 on_each_cpu(__gator_timer_offline, NULL, 1);
472
473 // output a final sync point
474 gator_buffer_write_packed_int(0, PROTOCOL_CPU_SYNC);
475 gator_buffer_commit(0);
476 }
477}
478
479static void __gator_timer_online(void *unused)
480{
481 int cpu = smp_processor_id();
482 if (!per_cpu(hrtimer_is_active, cpu)) {
483 struct gator_interface *gi;
484 struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu);
485 hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
486 hrtimer->function = gator_hrtimer_notify;
487 hrtimer_start(hrtimer, profiling_interval, HRTIMER_MODE_REL_PINNED);
488 per_cpu(gator_cpu_tick, cpu) = 0;
489 per_cpu(gator_first_time, cpu) = 1;
490 per_cpu(hrtimer_is_active, cpu) = 1;
491
492 // online any events
493 list_for_each_entry(gi, &gator_events, list)
494 if (gi->online)
495 gi->online();
496 }
497}
498
499int gator_timer_online(unsigned long setup)
500{
501 if (!setup) {
502 pr_err("gator: cannot start due to a system tick value of zero");
503 return -1;
504 } else if (hrtimer_running) {
505 pr_notice("gator: high res timer already running");
506 return 0;
507 }
508
509 hrtimer_running = 1;
510
511 // calculate profiling interval
512 profiling_interval = ns_to_ktime(1000000000UL / setup);
513
514 // timer interrupt
515 gator_master_tick = 0;
516 on_each_cpu(__gator_timer_online, NULL, 1);
517
518 return 0;
519}
520
521static uint64_t gator_get_time(void)
522{
523 struct timespec ts;
524 uint64_t timestamp;
525
526 ktime_get_ts(&ts);
527 timestamp = timespec_to_ns(&ts);
528
529 return timestamp;
530}
531
532/******************************************************************************
533 * cpu online notifier
534 ******************************************************************************/
535static int __cpuinit gator_cpu_notify(struct notifier_block *self,
536 unsigned long action, void *hcpu)
537{
538 long cpu = (long)hcpu;
539
540 switch (action) {
541 case CPU_ONLINE:
542 case CPU_ONLINE_FROZEN:
543 smp_call_function_single(cpu, __gator_timer_online, NULL, 1);
544 break;
545 case CPU_DOWN_PREPARE:
546 case CPU_DOWN_PREPARE_FROZEN:
547 smp_call_function_single(cpu, __gator_timer_offline, NULL, 1);
548 break;
549 }
550
551 return NOTIFY_OK;
552}
553
554static struct notifier_block __refdata gator_cpu_notifier = {
555 .notifier_call = gator_cpu_notify,
556};
557
558static int gator_notifier_start(void)
559{
560 return register_hotcpu_notifier(&gator_cpu_notifier);
561}
562
563static void gator_notifier_stop(void)
564{
565 unregister_hotcpu_notifier(&gator_cpu_notifier);
566}
567
568/******************************************************************************
569 * Main
570 ******************************************************************************/
571int gator_events_install(struct gator_interface *interface)
572{
573 list_add_tail(&interface->list, &gator_events);
574
575 return 0;
576}
577
578int gator_events_get_key(void)
579{
580 static int key;
581
582 return key++;
583}
584
585static int gator_init(void)
586{
587 int i;
588
589 if (gator_timer_init())
590 return -1;
591 if (gator_trace_sched_init())
592 return -1;
593 if (gator_annotate_init())
594 return -1;
595
596 // events sources (gator_events.h, generated by gator_events.sh)
597 for (i = 0; i < ARRAY_SIZE(gator_events_list); i++)
598 if (gator_events_list[i])
599 gator_events_list[i]();
600
601 return 0;
602}
603
604static int gator_start(void)
605{
606 struct gator_interface *gi;
607
608 // start all events
609 list_for_each_entry(gi, &gator_events, list) {
610 if (gi->start && gi->start() != 0) {
611 struct list_head *ptr = gi->list.prev;
612
613 while (ptr != &gator_events) {
614 gi = list_entry(ptr, struct gator_interface,
615 list);
616
617 if (gi->stop)
618 gi->stop();
619
620 ptr = ptr->prev;
621 }
622 goto events_failure;
623 }
624 }
625
626 if (gator_annotate_start())
627 goto annotate_failure;
628 if (gator_trace_sched_start())
629 goto sched_failure;
630 if (gator_timer_online(gator_timer_count))
631 goto timer_failure;
632 if (gator_notifier_start())
633 goto notifier_failure;
634
635 return 0;
636
637notifier_failure:
638 gator_timer_offline();
639timer_failure:
640 gator_trace_sched_stop();
641sched_failure:
642 gator_annotate_stop();
643annotate_failure:
644events_failure:
645
646 return -1;
647}
648
649static void gator_stop(void)
650{
651 struct gator_interface *gi;
652
653 // stop all events
654 list_for_each_entry(gi, &gator_events, list)
655 if (gi->stop)
656 gi->stop();
657
658 gator_annotate_stop();
659 gator_trace_sched_stop();
660
661 // stop all interrupt callback reads before tearing down other interfaces
662 gator_timer_offline();
663 gator_notifier_stop();
664}
665
666static void gator_exit(void)
667{
668 gator_annotate_exit();
669}
670
671/******************************************************************************
672 * Filesystem
673 ******************************************************************************/
674/* fopen("buffer") */
675static int gator_op_setup(void)
676{
677 int err = 0;
678 int cpu;
679
680 mutex_lock(&start_mutex);
681
682 use_buffer_size = gator_buffer_size;
683 use_buffer_mask = use_buffer_size - 1;
684
685 // must be a power of 2
686 if (use_buffer_size & (use_buffer_size - 1)) {
687 err = -ENOEXEC;
688 goto setup_error;
689 }
690
691 gator_net_traffic = 0;
692
693 gator_commit_read = gator_commit_write = 0;
694 gator_commit = vmalloc(COMMIT_SIZE * sizeof(int));
695 if (!gator_commit) {
696 err = -ENOMEM;
697 goto setup_error;
698 }
699
700 for_each_present_cpu(cpu) {
701 per_cpu(use_buffer, cpu) = vmalloc(use_buffer_size);
702 if (!per_cpu(use_buffer, cpu)) {
703 err = -ENOMEM;
704 goto setup_error;
705 }
706
707 per_cpu(gator_cpu_sync, cpu) = 0;
708 per_cpu(gator_cpu_tick, cpu) = 0;
709
710 per_cpu(use_buffer_seq, cpu) = 0;
711 per_cpu(use_buffer_read, cpu) = 0;
712 per_cpu(use_buffer_write, cpu) = 0;
713 gator_buffer_header(cpu);
714 }
715
716setup_error:
717 mutex_unlock(&start_mutex);
718 return err;
719}
720
721/* Actually start profiling (echo 1>/dev/gator/enable) */
722static int gator_op_start(void)
723{
724 int err = 0;
725
726 mutex_lock(&start_mutex);
727
728 if (gator_started || gator_start() || cookies_initialize())
729 err = -EINVAL;
730 else
731 gator_started = 1;
732
733 mutex_unlock(&start_mutex);
734
735 return err;
736}
737
738/* echo 0>/dev/gator/enable */
739static void gator_op_stop(void)
740{
741 mutex_lock(&start_mutex);
742
743 if (gator_started) {
744 gator_stop();
745
746 mutex_lock(&gator_buffer_mutex);
747
748 gator_started = 0;
749 cookies_release();
750 wake_up(&gator_buffer_wait);
751
752 mutex_unlock(&gator_buffer_mutex);
753 }
754
755 mutex_unlock(&start_mutex);
756}
757
758static void gator_shutdown(void)
759{
760 int cpu;
761
762 mutex_lock(&start_mutex);
763
764 vfree(gator_commit);
765 gator_commit = NULL;
766
767 for_each_present_cpu(cpu) {
768 mutex_lock(&gator_buffer_mutex);
769 vfree(per_cpu(use_buffer, cpu));
770 per_cpu(use_buffer, cpu) = NULL;
771 per_cpu(use_buffer_seq, cpu) = 0;
772 per_cpu(use_buffer_read, cpu) = 0;
773 per_cpu(use_buffer_write, cpu) = 0;
774 mutex_unlock(&gator_buffer_mutex);
775 }
776
777 mutex_unlock(&start_mutex);
778}
779
780static int gator_set_backtrace(unsigned long val)
781{
782 int err = 0;
783
784 mutex_lock(&start_mutex);
785
786 if (gator_started)
787 err = -EBUSY;
788 else
789 gator_backtrace_depth = val;
790
791 mutex_unlock(&start_mutex);
792
793 return err;
794}
795
796static ssize_t enable_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
797{
798 return gatorfs_ulong_to_user(gator_started, buf, count, offset);
799}
800
801static ssize_t enable_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
802{
803 unsigned long val;
804 int retval;
805
806 if (*offset)
807 return -EINVAL;
808
809 retval = gatorfs_ulong_from_user(&val, buf, count);
810 if (retval)
811 return retval;
812
813 if (val)
814 retval = gator_op_start();
815 else
816 gator_op_stop();
817
818 if (retval)
819 return retval;
820 return count;
821}
822
823static const struct file_operations enable_fops = {
824 .read = enable_read,
825 .write = enable_write,
826};
827
828static int event_buffer_open(struct inode *inode, struct file *file)
829{
830 int err = -EPERM;
831
832 if (!capable(CAP_SYS_ADMIN))
833 return -EPERM;
834
835 if (test_and_set_bit_lock(0, &gator_buffer_opened))
836 return -EBUSY;
837
838 if ((err = gator_op_setup()))
839 goto fail;
840
841 /* NB: the actual start happens from userspace
842 * echo 1 >/dev/gator/enable
843 */
844
845 return 0;
846
847fail:
848 __clear_bit_unlock(0, &gator_buffer_opened);
849 return err;
850}
851
852static int event_buffer_release(struct inode *inode, struct file *file)
853{
854 gator_op_stop();
855 gator_shutdown();
856 __clear_bit_unlock(0, &gator_buffer_opened);
857 return 0;
858}
859
860static ssize_t event_buffer_read(struct file *file, char __user *buf,
861 size_t count, loff_t *offset)
862{
863 int retval = -EINVAL;
864 int commit, length1, length2, read;
865 char *buffer1, *buffer2;
866 char annotate_header[6];
867 int cpu;
868
869 /* do not handle partial reads */
870 if (count != use_buffer_size || *offset)
871 return -EINVAL;
872
873 // sleep until the condition is true or a signal is received
874 // the condition is checked each time gator_buffer_wait is woken up
875 wait_event_interruptible(gator_buffer_wait, buffer_commit_ready() || gator_annotate_ready() || !gator_started);
876
877 if (signal_pending(current))
878 return -EINTR;
879
880 retval = -EFAULT;
881
882 mutex_lock(&gator_buffer_mutex);
883
884 if (buffer_commit_ready()) {
885 buffer_commit_read(&cpu, &read, &commit);
886
887 /* May happen if the buffer is freed during pending reads. */
888 if (!per_cpu(use_buffer, cpu)) {
889 retval = -EFAULT;
890 goto out;
891 }
892
893 /* determine the size of two halves */
894 length1 = commit - read;
895 length2 = 0;
896 buffer1 = &(per_cpu(use_buffer, cpu)[read]);
897 buffer2 = &(per_cpu(use_buffer, cpu)[0]);
898 if (length1 < 0) {
899 length1 = use_buffer_size - read;
900 length2 = commit;
901 }
902 } else if (gator_annotate_ready()) {
903 length2 = gator_annotate_read(&buffer2);
904 if (!length2)
905 goto out;
906 annotate_header[0] = PROTOCOL_ANNOTATE;
907 length1 = gator_write_packed_int(&annotate_header[1], length2) + 1;
908 buffer1 = annotate_header;
909 } else {
910 retval = 0;
911 goto out;
912 }
913
914 /* start, middle or end */
915 if (length1 > 0) {
916 if (copy_to_user(&buf[0], buffer1, length1)) {
917 goto out;
918 }
919 }
920
921 /* possible wrap around */
922 if (length2 > 0) {
923 if (copy_to_user(&buf[length1], buffer2, length2)) {
924 goto out;
925 }
926 }
927
928 retval = length1 + length2;
929
930 /* kick just in case we've lost an SMP event */
931 wake_up(&gator_buffer_wait);
932
933out:
934 // only adjust network stats if in streaming mode
935 if (gator_streaming)
936 gator_net_traffic += retval;
937 mutex_unlock(&gator_buffer_mutex);
938 return retval;
939}
940
941const struct file_operations gator_event_buffer_fops = {
942 .open = event_buffer_open,
943 .release = event_buffer_release,
944 .read = event_buffer_read,
945};
946
947static ssize_t depth_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
948{
949 return gatorfs_ulong_to_user(gator_backtrace_depth, buf, count,
950 offset);
951}
952
953static ssize_t depth_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
954{
955 unsigned long val;
956 int retval;
957
958 if (*offset)
959 return -EINVAL;
960
961 retval = gatorfs_ulong_from_user(&val, buf, count);
962 if (retval)
963 return retval;
964
965 retval = gator_set_backtrace(val);
966
967 if (retval)
968 return retval;
969 return count;
970}
971
972static const struct file_operations depth_fops = {
973 .read = depth_read,
974 .write = depth_write
975};
976
977static const char gator_cpu_type[] = "gator";
978
979static ssize_t cpu_type_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
980{
981 return gatorfs_str_to_user(gator_cpu_type, buf, count, offset);
982}
983
984static const struct file_operations cpu_type_fops = {
985 .read = cpu_type_read,
986};
987
988void gator_op_create_files(struct super_block *sb, struct dentry *root)
989{
990 struct dentry *dir;
991 struct gator_interface *gi;
992 int cpu;
993
994 /* reinitialize default values */
995 gator_cpu_cores = 0;
996 for_each_present_cpu(cpu) {
997 gator_cpu_cores++;
998 }
999 gator_buffer_size = BUFFER_SIZE_DEFAULT;
1000 gator_streaming = 1;
1001
1002 gatorfs_create_file(sb, root, "enable", &enable_fops);
1003 gatorfs_create_file(sb, root, "buffer", &gator_event_buffer_fops);
1004 gatorfs_create_file(sb, root, "backtrace_depth", &depth_fops);
1005 gatorfs_create_file(sb, root, "cpu_type", &cpu_type_fops);
1006 gatorfs_create_ulong(sb, root, "cpu_cores", &gator_cpu_cores);
1007 gatorfs_create_ulong(sb, root, "buffer_size", &gator_buffer_size);
1008 gatorfs_create_ulong(sb, root, "tick", &gator_timer_count);
1009 gatorfs_create_ulong(sb, root, "streaming", &gator_streaming);
1010 gatorfs_create_ro_ulong(sb, root, "version", &gator_protocol_version);
1011
1012 // Annotate interface
1013 gator_annotate_create_files(sb, root);
1014
1015 // Linux Events
1016 dir = gatorfs_mkdir(sb, root, "events");
1017 list_for_each_entry(gi, &gator_events, list)
1018 if (gi->create_files)
1019 gi->create_files(sb, dir);
1020}
1021
1022/******************************************************************************
1023 * Module
1024 ******************************************************************************/
1025static int __init gator_module_init(void)
1026{
1027 if (gatorfs_register()) {
1028 return -1;
1029 }
1030
1031 if (gator_init()) {
1032 gatorfs_unregister();
1033 return -1;
1034 }
1035
1036#ifdef GATOR_DEBUG
1037 pr_err("gator_module_init");
1038#endif
1039 return 0;
1040}
1041
1042static void __exit gator_module_exit(void)
1043{
1044#ifdef GATOR_DEBUG
1045 pr_err("gator_module_exit");
1046#endif
1047 tracepoint_synchronize_unregister();
1048 gatorfs_unregister();
1049 gator_exit();
1050}
1051
1052module_init(gator_module_init);
1053module_exit(gator_module_exit);
1054
1055MODULE_LICENSE("GPL");
1056MODULE_AUTHOR("ARM Ltd");
1057MODULE_DESCRIPTION("Gator system profiler");