summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'driver/gator_main.c')
-rw-r--r--driver/gator_main.c91
1 files changed, 58 insertions, 33 deletions
diff --git a/driver/gator_main.c b/driver/gator_main.c
index 91744ad..36e951b 100644
--- a/driver/gator_main.c
+++ b/driver/gator_main.c
@@ -7,7 +7,7 @@
7 * 7 *
8 */ 8 */
9 9
10static unsigned long gator_protocol_version = 6; 10static unsigned long gator_protocol_version = 7;
11 11
12#include <linux/slab.h> 12#include <linux/slab.h>
13#include <linux/cpu.h> 13#include <linux/cpu.h>
@@ -17,6 +17,8 @@ static unsigned long gator_protocol_version = 6;
17#include <linux/hardirq.h> 17#include <linux/hardirq.h>
18#include <linux/highmem.h> 18#include <linux/highmem.h>
19#include <linux/pagemap.h> 19#include <linux/pagemap.h>
20#include <linux/suspend.h>
21#include <asm/stacktrace.h>
20#include <asm/uaccess.h> 22#include <asm/uaccess.h>
21 23
22#include "gator.h" 24#include "gator.h"
@@ -51,7 +53,7 @@ static unsigned long gator_protocol_version = 6;
51/****************************************************************************** 53/******************************************************************************
52 * DEFINES 54 * DEFINES
53 ******************************************************************************/ 55 ******************************************************************************/
54#define TIMER_BUFFER_SIZE_DEFAULT (256*1024) 56#define TIMER_BUFFER_SIZE_DEFAULT (512*1024)
55#define EVENT_BUFFER_SIZE_DEFAULT (128*1024) 57#define EVENT_BUFFER_SIZE_DEFAULT (128*1024)
56 58
57#define NO_COOKIE 0UL 59#define NO_COOKIE 0UL
@@ -267,11 +269,12 @@ static void gator_add_trace(int cpu, int buftype, unsigned int address)
267 269
268static void gator_add_sample(int cpu, int buftype, struct pt_regs * const regs) 270static void gator_add_sample(int cpu, int buftype, struct pt_regs * const regs)
269{ 271{
270 struct module *mod;
271 unsigned int addr, cookie = 0;
272 int inKernel = regs ? !user_mode(regs) : 1; 272 int inKernel = regs ? !user_mode(regs) : 1;
273 unsigned long exec_cookie = inKernel ? NO_COOKIE : get_exec_cookie(cpu, buftype, current); 273 unsigned long exec_cookie = inKernel ? NO_COOKIE : get_exec_cookie(cpu, buftype, current);
274 274
275 if (!regs)
276 return;
277
275 gator_buffer_write_packed_int(cpu, buftype, MESSAGE_START_BACKTRACE); 278 gator_buffer_write_packed_int(cpu, buftype, MESSAGE_START_BACKTRACE);
276 gator_buffer_write_packed_int64(cpu, buftype, gator_get_time()); 279 gator_buffer_write_packed_int64(cpu, buftype, gator_get_time());
277 gator_buffer_write_packed_int(cpu, buftype, exec_cookie); 280 gator_buffer_write_packed_int(cpu, buftype, exec_cookie);
@@ -279,25 +282,15 @@ static void gator_add_sample(int cpu, int buftype, struct pt_regs * const regs)
279 gator_buffer_write_packed_int(cpu, buftype, (unsigned int)current->pid); 282 gator_buffer_write_packed_int(cpu, buftype, (unsigned int)current->pid);
280 gator_buffer_write_packed_int(cpu, buftype, inKernel); 283 gator_buffer_write_packed_int(cpu, buftype, inKernel);
281 284
282 // get_irq_regs() will return NULL outside of IRQ context (e.g. nested IRQ) 285 if (inKernel) {
283 if (regs) { 286 kernel_backtrace(cpu, buftype, regs);
284 if (inKernel) { 287 } else {
285 addr = PC_REG; 288 // Cookie+PC
286 mod = __module_address(addr); 289 gator_add_trace(cpu, buftype, PC_REG);
287 if (mod) { 290
288 cookie = get_cookie(cpu, buftype, current, NULL, mod, true); 291 // Backtrace
289 addr = addr - (unsigned long)mod->module_core; 292 if (gator_backtrace_depth)
290 } 293 arm_backtrace_eabi(cpu, buftype, regs, gator_backtrace_depth);
291 gator_buffer_write_packed_int(cpu, buftype, addr & ~1);
292 gator_buffer_write_packed_int(cpu, buftype, cookie);
293 } else {
294 // Cookie+PC
295 gator_add_trace(cpu, buftype, PC_REG);
296
297 // Backtrace
298 if (gator_backtrace_depth)
299 arm_backtrace_eabi(cpu, buftype, regs, gator_backtrace_depth);
300 }
301 } 294 }
302 295
303 gator_buffer_write_packed_int(cpu, buftype, MESSAGE_END_BACKTRACE); 296 gator_buffer_write_packed_int(cpu, buftype, MESSAGE_END_BACKTRACE);
@@ -352,11 +345,12 @@ static void gator_timer_interrupt(void)
352 } 345 }
353 } else if (gi->read64) { 346 } else if (gi->read64) {
354 len = gi->read64(&buffer64); 347 len = gi->read64(&buffer64);
355 if (len > 0) 348 if (len > 0) {
356 gator_buffer_write_packed_int(cpu, buftype, len); 349 gator_buffer_write_packed_int(cpu, buftype, len);
357 for (i = 0; i < len; i++) { 350 for (i = 0; i < len; i++) {
358 gator_buffer_write_packed_int64(cpu, buftype, buffer64[i]); 351 gator_buffer_write_packed_int64(cpu, buftype, buffer64[i]);
359 } 352 }
353 }
360 } 354 }
361 } 355 }
362 gator_buffer_write_packed_int(cpu, buftype, 0); 356 gator_buffer_write_packed_int(cpu, buftype, 0);
@@ -460,29 +454,28 @@ static uint64_t gator_get_time(void)
460 struct timespec ts; 454 struct timespec ts;
461 uint64_t timestamp; 455 uint64_t timestamp;
462 456
463 ktime_get_ts(&ts); 457 getnstimeofday(&ts);
464 timestamp = timespec_to_ns(&ts); 458 timestamp = timespec_to_ns(&ts);
465 459
466 return timestamp; 460 return timestamp;
467} 461}
468 462
469/****************************************************************************** 463/******************************************************************************
470 * cpu online notifier 464 * cpu online and pm notifiers
471 ******************************************************************************/ 465 ******************************************************************************/
472static int __cpuinit gator_cpu_notify(struct notifier_block *self, 466static int __cpuinit gator_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
473 unsigned long action, void *hcpu)
474{ 467{
475 long cpu = (long)hcpu; 468 long cpu = (long)hcpu;
476 469
477 switch (action) { 470 switch (action) {
478 case CPU_ONLINE:
479 case CPU_ONLINE_FROZEN:
480 smp_call_function_single(cpu, __gator_timer_online, NULL, 1);
481 break;
482 case CPU_DOWN_PREPARE: 471 case CPU_DOWN_PREPARE:
483 case CPU_DOWN_PREPARE_FROZEN: 472 case CPU_DOWN_PREPARE_FROZEN:
484 smp_call_function_single(cpu, __gator_timer_offline, NULL, 1); 473 smp_call_function_single(cpu, __gator_timer_offline, NULL, 1);
485 break; 474 break;
475 case CPU_ONLINE:
476 case CPU_ONLINE_FROZEN:
477 smp_call_function_single(cpu, __gator_timer_online, NULL, 1);
478 break;
486 } 479 }
487 480
488 return NOTIFY_OK; 481 return NOTIFY_OK;
@@ -492,13 +485,45 @@ static struct notifier_block __refdata gator_cpu_notifier = {
492 .notifier_call = gator_cpu_notify, 485 .notifier_call = gator_cpu_notify,
493}; 486};
494 487
488// n.b. calling "on_each_cpu" only runs on those that are online
489// Registered linux events are not disabled, so their counters will continue to collect
490static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void *dummy)
491{
492 switch (event) {
493 case PM_HIBERNATION_PREPARE:
494 case PM_SUSPEND_PREPARE:
495 unregister_hotcpu_notifier(&gator_cpu_notifier);
496 unregister_scheduler_tracepoints();
497 on_each_cpu(trace_sched_insert_idle, NULL, 1);
498 on_each_cpu(__gator_timer_offline, NULL, 1);
499 break;
500 case PM_POST_HIBERNATION:
501 case PM_POST_SUSPEND:
502 on_each_cpu(__gator_timer_online, NULL, 1);
503 register_scheduler_tracepoints();
504 register_hotcpu_notifier(&gator_cpu_notifier);
505 break;
506 }
507
508 return NOTIFY_OK;
509}
510
511static struct notifier_block gator_pm_notifier = {
512 .notifier_call = gator_pm_notify,
513};
514
495static int gator_notifier_start(void) 515static int gator_notifier_start(void)
496{ 516{
497 return register_hotcpu_notifier(&gator_cpu_notifier); 517 int retval;
518 retval = register_hotcpu_notifier(&gator_cpu_notifier);
519 if (retval == 0)
520 retval = register_pm_notifier(&gator_pm_notifier);
521 return retval;
498} 522}
499 523
500static void gator_notifier_stop(void) 524static void gator_notifier_stop(void)
501{ 525{
526 unregister_pm_notifier(&gator_pm_notifier);
502 unregister_hotcpu_notifier(&gator_cpu_notifier); 527 unregister_hotcpu_notifier(&gator_cpu_notifier);
503} 528}
504 529