aboutsummaryrefslogtreecommitdiff
path: root/drivers/gator/gator_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gator/gator_main.c')
-rw-r--r--drivers/gator/gator_main.c290
1 files changed, 71 insertions, 219 deletions
diff --git a/drivers/gator/gator_main.c b/drivers/gator/gator_main.c
index 19f51c7cd8e..e67f7c5cc61 100644
--- a/drivers/gator/gator_main.c
+++ b/drivers/gator/gator_main.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) ARM Limited 2010-2013. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2014. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -8,7 +8,7 @@
*/
// This version must match the gator daemon version
-#define PROTOCOL_VERSION 17
+#define PROTOCOL_VERSION 18
static unsigned long gator_protocol_version = PROTOCOL_VERSION;
#include <linux/slab.h>
@@ -55,9 +55,9 @@ static unsigned long gator_protocol_version = PROTOCOL_VERSION;
#if (GATOR_PERF_SUPPORT) && (!(GATOR_PERF_PMU_SUPPORT))
#ifndef CONFIG_PERF_EVENTS
-#warning gator requires the kernel to have CONFIG_PERF_EVENTS defined to support pmu hardware counters
+#error gator requires the kernel to have CONFIG_PERF_EVENTS defined to support pmu hardware counters
#elif !defined CONFIG_HW_PERF_EVENTS
-#warning gator requires the kernel to have CONFIG_HW_PERF_EVENTS defined to support pmu hardware counters
+#error gator requires the kernel to have CONFIG_HW_PERF_EVENTS defined to support pmu hardware counters
#endif
#endif
@@ -89,20 +89,27 @@ static unsigned long gator_protocol_version = PROTOCOL_VERSION;
#define MESSAGE_END_BACKTRACE 1
+// Name Frame Messages
#define MESSAGE_COOKIE 1
#define MESSAGE_THREAD_NAME 2
-#define HRTIMER_CORE_NAME 3
#define MESSAGE_LINK 4
+// GPU Trace Frame Messages
#define MESSAGE_GPU_START 1
#define MESSAGE_GPU_STOP 2
+// Scheduler Trace Frame Messages
#define MESSAGE_SCHED_SWITCH 1
#define MESSAGE_SCHED_EXIT 2
#define MESSAGE_SCHED_START 3
+// Idle Frame Messages
#define MESSAGE_IDLE_ENTER 1
-#define MESSAGE_IDLE_EXIT 2
+#define MESSAGE_IDLE_EXIT 2
+
+// Summary Frame Messages
+#define MESSAGE_SUMMARY 1
+#define MESSAGE_CORE_NAME 3
#define MAXSIZE_PACK32 5
#define MAXSIZE_PACK64 10
@@ -154,7 +161,13 @@ bool event_based_sampling;
static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait);
static DECLARE_WAIT_QUEUE_HEAD(gator_annotate_wait);
static struct timer_list gator_buffer_wake_up_timer;
-static bool gator_buffer_wake_stop;
+static bool gator_buffer_wake_run;
+// Initialize semaphore unlocked to initialize memory values
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
+static DECLARE_MUTEX(gator_buffer_wake_sem);
+#else
+static DEFINE_SEMAPHORE(gator_buffer_wake_sem);
+#endif
static struct task_struct *gator_buffer_wake_thread;
static LIST_HEAD(gator_events);
@@ -164,21 +177,19 @@ static bool printed_monotonic_warning;
static bool sent_core_name[NR_CPUS];
+static DEFINE_PER_CPU(bool, in_scheduler_context);
+
/******************************************************************************
* Prototypes
******************************************************************************/
-static void buffer_check(int cpu, int buftype, u64 time);
-static void gator_commit_buffer(int cpu, int buftype, u64 time);
-static int buffer_bytes_available(int cpu, int buftype);
-static bool buffer_check_space(int cpu, int buftype, int bytes);
-static int contiguous_space_available(int cpu, int bufytpe);
-static void gator_buffer_write_packed_int(int cpu, int buftype, int x);
-static void gator_buffer_write_packed_int64(int cpu, int buftype, long long x);
-static void gator_buffer_write_bytes(int cpu, int buftype, const char *x, int len);
-static void gator_buffer_write_string(int cpu, int buftype, const char *x);
-static void gator_add_trace(int cpu, unsigned long address);
-static void gator_add_sample(int cpu, struct pt_regs *const regs, u64 time);
static u64 gator_get_time(void);
+static void gator_op_create_files(struct super_block *sb, struct dentry *root);
+
+// gator_buffer is protected by being per_cpu and by having IRQs disabled when writing to it.
+// Most marshal_* calls take care of this except for marshal_cookie*, marshal_backtrace* and marshal_frame where the caller is responsible for doing so.
+// No synchronization is needed with the backtrace buffer as it is per cpu and is only used from the hrtimer.
+// The annotate_lock must be held when using the annotation buffer as it is not per cpu.
+// collect_counters which is the sole writer to the block counter frame is additionally protected by the per cpu collecting flag
// Size of the buffer, must be a power of 2. Effectively constant, set in gator_op_setup.
static uint32_t gator_buffer_size[NUM_GATOR_BUFS];
@@ -229,8 +240,10 @@ GATOR_EVENTS_LIST
/******************************************************************************
* Application Includes
******************************************************************************/
+#include "gator_fs.c"
+#include "gator_buffer_write.c"
+#include "gator_buffer.c"
#include "gator_marshaling.c"
-#include "gator_hrtimer_perf.c"
#include "gator_hrtimer_gator.c"
#include "gator_cookies.c"
#include "gator_annotate.c"
@@ -238,14 +251,12 @@ GATOR_EVENTS_LIST
#include "gator_trace_power.c"
#include "gator_trace_gpu.c"
#include "gator_backtrace.c"
-#include "gator_fs.c"
-#include "gator_pack.c"
/******************************************************************************
* Misc
******************************************************************************/
-const struct gator_cpu gator_cpus[] = {
+static const struct gator_cpu gator_cpus[] = {
{
.cpuid = ARM1136,
.core_name = "ARM1136",
@@ -277,52 +288,53 @@ const struct gator_cpu gator_cpus[] = {
{
.cpuid = CORTEX_A5,
.core_name = "Cortex-A5",
- .pmu_name = "ARMv7_Cortex_A5",
- .pmnc_name = "ARM_Cortex-A5",
+ .pmnc_name = "ARMv7_Cortex_A5",
.dt_name = "arm,cortex-a5",
.pmnc_counters = 2,
},
{
.cpuid = CORTEX_A7,
.core_name = "Cortex-A7",
- .pmu_name = "ARMv7_Cortex_A7",
- .pmnc_name = "ARM_Cortex-A7",
+ .pmnc_name = "ARMv7_Cortex_A7",
.dt_name = "arm,cortex-a7",
.pmnc_counters = 4,
},
{
.cpuid = CORTEX_A8,
.core_name = "Cortex-A8",
- .pmu_name = "ARMv7_Cortex_A8",
- .pmnc_name = "ARM_Cortex-A8",
+ .pmnc_name = "ARMv7_Cortex_A8",
.dt_name = "arm,cortex-a8",
.pmnc_counters = 4,
},
{
.cpuid = CORTEX_A9,
.core_name = "Cortex-A9",
- .pmu_name = "ARMv7_Cortex_A9",
- .pmnc_name = "ARM_Cortex-A9",
+ .pmnc_name = "ARMv7_Cortex_A9",
.dt_name = "arm,cortex-a9",
.pmnc_counters = 6,
},
{
.cpuid = CORTEX_A12,
.core_name = "Cortex-A12",
- .pmu_name = "ARMv7_Cortex_A12",
- .pmnc_name = "ARM_Cortex-A12",
+ .pmnc_name = "ARMv7_Cortex_A12",
.dt_name = "arm,cortex-a12",
.pmnc_counters = 6,
},
{
.cpuid = CORTEX_A15,
.core_name = "Cortex-A15",
- .pmu_name = "ARMv7_Cortex_A15",
- .pmnc_name = "ARM_Cortex-A15",
+ .pmnc_name = "ARMv7_Cortex_A15",
.dt_name = "arm,cortex-a15",
.pmnc_counters = 6,
},
{
+ .cpuid = CORTEX_A17,
+ .core_name = "Cortex-A17",
+ .pmnc_name = "ARMv7_Cortex_A17",
+ .dt_name = "arm,cortex-a17",
+ .pmnc_counters = 6,
+ },
+ {
.cpuid = SCORPION,
.core_name = "Scorpion",
.pmnc_name = "Scorpion",
@@ -401,7 +413,7 @@ const struct gator_cpu *gator_find_cpu_by_pmu_name(const char *const name)
for (i = 0; gator_cpus[i].cpuid != 0; ++i) {
const struct gator_cpu *const gator_cpu = &gator_cpus[i];
- if (gator_cpu->pmu_name != NULL && strcmp(gator_cpu->pmu_name, name) == 0) {
+ if (gator_cpu->pmnc_name != NULL && strcmp(gator_cpu->pmnc_name, name) == 0) {
return gator_cpu;
}
}
@@ -431,10 +443,15 @@ static void gator_buffer_wake_up(unsigned long data)
static int gator_buffer_wake_func(void *data)
{
- while (!gator_buffer_wake_stop) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule();
- if (gator_buffer_wake_stop) {
+ for (;;) {
+ if (down_killable(&gator_buffer_wake_sem)) {
+ break;
+ }
+
+ // Eat up any pending events
+ while (!down_trylock(&gator_buffer_wake_sem));
+
+ if (!gator_buffer_wake_run) {
break;
}
@@ -464,173 +481,6 @@ static bool buffer_commit_ready(int *cpu, int *buftype)
}
/******************************************************************************
- * Buffer management
- ******************************************************************************/
-static int buffer_bytes_available(int cpu, int buftype)
-{
- int remaining, filled;
-
- filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_read, cpu)[buftype];
- if (filled < 0) {
- filled += gator_buffer_size[buftype];
- }
-
- remaining = gator_buffer_size[buftype] - filled;
-
- if (per_cpu(buffer_space_available, cpu)[buftype]) {
- // Give some extra room; also allows space to insert the overflow error packet
- remaining -= 200;
- } else {
- // Hysteresis, prevents multiple overflow messages
- remaining -= 2000;
- }
-
- return remaining;
-}
-
-static int contiguous_space_available(int cpu, int buftype)
-{
- int remaining = buffer_bytes_available(cpu, buftype);
- int contiguous = gator_buffer_size[buftype] - per_cpu(gator_buffer_write, cpu)[buftype];
- if (remaining < contiguous)
- return remaining;
- else
- return contiguous;
-}
-
-static bool buffer_check_space(int cpu, int buftype, int bytes)
-{
- int remaining = buffer_bytes_available(cpu, buftype);
-
- if (remaining < bytes) {
- per_cpu(buffer_space_available, cpu)[buftype] = false;
- } else {
- per_cpu(buffer_space_available, cpu)[buftype] = true;
- }
-
- return per_cpu(buffer_space_available, cpu)[buftype];
-}
-
-static void gator_buffer_write_bytes(int cpu, int buftype, const char *x, int len)
-{
- int i;
- u32 write = per_cpu(gator_buffer_write, cpu)[buftype];
- u32 mask = gator_buffer_mask[buftype];
- char *buffer = per_cpu(gator_buffer, cpu)[buftype];
-
- for (i = 0; i < len; i++) {
- buffer[write] = x[i];
- write = (write + 1) & mask;
- }
-
- per_cpu(gator_buffer_write, cpu)[buftype] = write;
-}
-
-static void gator_buffer_write_string(int cpu, int buftype, const char *x)
-{
- int len = strlen(x);
- gator_buffer_write_packed_int(cpu, buftype, len);
- gator_buffer_write_bytes(cpu, buftype, x, len);
-}
-
-static void gator_commit_buffer(int cpu, int buftype, u64 time)
-{
- int type_length, commit, length, byte;
-
- if (!per_cpu(gator_buffer, cpu)[buftype])
- return;
-
- // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
- type_length = gator_response_type ? 1 : 0;
- commit = per_cpu(gator_buffer_commit, cpu)[buftype];
- length = per_cpu(gator_buffer_write, cpu)[buftype] - commit;
- if (length < 0) {
- length += gator_buffer_size[buftype];
- }
- length = length - type_length - sizeof(s32);
-
- if (length <= FRAME_HEADER_SIZE) {
- // Nothing to write, only the frame header is present
- return;
- }
-
- for (byte = 0; byte < sizeof(s32); byte++) {
- per_cpu(gator_buffer, cpu)[buftype][(commit + type_length + byte) & gator_buffer_mask[buftype]] = (length >> byte * 8) & 0xFF;
- }
-
- per_cpu(gator_buffer_commit, cpu)[buftype] = per_cpu(gator_buffer_write, cpu)[buftype];
-
- if (gator_live_rate > 0) {
- while (time > per_cpu(gator_buffer_commit_time, cpu)) {
- per_cpu(gator_buffer_commit_time, cpu) += gator_live_rate;
- }
- }
-
- marshal_frame(cpu, buftype);
-
- // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
- if (per_cpu(in_scheduler_context, cpu)) {
-#ifndef CONFIG_PREEMPT_RT_FULL
- // mod_timer can not be used in interrupt context in RT-Preempt full
- mod_timer(&gator_buffer_wake_up_timer, jiffies + 1);
-#endif
- } else {
- wake_up_process(gator_buffer_wake_thread);
- }
-}
-
-static void buffer_check(int cpu, int buftype, u64 time)
-{
- int filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_commit, cpu)[buftype];
- if (filled < 0) {
- filled += gator_buffer_size[buftype];
- }
- if (filled >= ((gator_buffer_size[buftype] * 3) / 4)) {
- gator_commit_buffer(cpu, buftype, time);
- }
-}
-
-static void gator_add_trace(int cpu, unsigned long address)
-{
- off_t offset = 0;
- unsigned long cookie = get_address_cookie(cpu, current, address & ~1, &offset);
-
- if (cookie == NO_COOKIE || cookie == UNRESOLVED_COOKIE) {
- offset = address;
- }
-
- marshal_backtrace(offset & ~1, cookie);
-}
-
-static void gator_add_sample(int cpu, struct pt_regs *const regs, u64 time)
-{
- bool inKernel;
- unsigned long exec_cookie;
-
- if (!regs)
- return;
-
- inKernel = !user_mode(regs);
- exec_cookie = get_exec_cookie(cpu, current);
-
- if (!marshal_backtrace_header(exec_cookie, current->tgid, current->pid, inKernel, time))
- return;
-
- if (inKernel) {
- kernel_backtrace(cpu, regs);
- } else {
- // Cookie+PC
- gator_add_trace(cpu, PC_REG);
-
- // Backtrace
- if (gator_backtrace_depth)
- arm_backtrace_eabi(cpu, regs, gator_backtrace_depth);
- }
-
- marshal_backtrace_footer(time);
-}
-
-/******************************************************************************
* hrtimer interrupt processing
******************************************************************************/
static void gator_timer_interrupt(void)
@@ -721,7 +571,8 @@ static void gator_timer_stop(void)
}
#if defined(__arm__) || defined(__aarch64__)
-static void gator_send_core_name(int cpu, const u32 cpuid, const struct gator_cpu *const gator_cpu) {
+static void gator_send_core_name(int cpu, const u32 cpuid, const struct gator_cpu *const gator_cpu)
+{
const char *core_name = NULL;
char core_name_buf[32];
@@ -788,7 +639,7 @@ static void gator_timer_online_dispatch(int cpu, bool migrate)
#include "gator_iks.c"
-int gator_timer_start(unsigned long sample_rate)
+static int gator_timer_start(unsigned long sample_rate)
{
int cpu;
@@ -944,7 +795,6 @@ static void gator_summary(void)
struct timespec ts;
char uname_buf[512];
void (*m2b)(struct timespec *ts);
- unsigned long flags;
snprintf(uname_buf, sizeof(uname_buf), "%s %s %s %s %s GNU/Linux", utsname()->sysname, utsname()->nodename, utsname()->release, utsname()->version, utsname()->machine);
@@ -959,14 +809,14 @@ static void gator_summary(void)
}
uptime = timespec_to_ns(&ts);
- // Disable interrupts as gator_get_time calls smp_processor_id to verify time is monotonic
- local_irq_save(flags);
+ // Disable preemption as gator_get_time calls smp_processor_id to verify time is monotonic
+ preempt_disable();
// Set monotonic_started to zero as gator_get_time is uptime minus monotonic_started
gator_monotonic_started = 0;
gator_monotonic_started = gator_get_time();
- local_irq_restore(flags);
marshal_summary(timestamp, uptime, gator_monotonic_started, uname_buf);
+ preempt_enable();
}
int gator_events_install(struct gator_interface *interface)
@@ -1019,7 +869,7 @@ static int gator_start(void)
unsigned long cpu, i;
struct gator_interface *gi;
- gator_buffer_wake_stop = false;
+ gator_buffer_wake_run = true;
if (IS_ERR(gator_buffer_wake_thread = kthread_run(gator_buffer_wake_func, NULL, "gator_bwake"))) {
goto bwake_failure;
}
@@ -1094,8 +944,9 @@ cookies_failure:
events_failure:
gator_migrate_stop();
migrate_failure:
- gator_buffer_wake_stop = true;
- wake_up_process(gator_buffer_wake_thread);
+ gator_buffer_wake_run = false;
+ up(&gator_buffer_wake_sem);
+ gator_buffer_wake_thread = NULL;
bwake_failure:
return -1;
@@ -1121,8 +972,9 @@ static void gator_stop(void)
gator_migrate_stop();
- gator_buffer_wake_stop = true;
- wake_up_process(gator_buffer_wake_thread);
+ gator_buffer_wake_run = false;
+ up(&gator_buffer_wake_sem);
+ gator_buffer_wake_thread = NULL;
}
/******************************************************************************
@@ -1417,7 +1269,7 @@ static ssize_t userspace_buffer_read(struct file *file, char __user *buf, size_t
return written > 0 ? written : -EFAULT;
}
-const struct file_operations gator_event_buffer_fops = {
+static const struct file_operations gator_event_buffer_fops = {
.open = userspace_buffer_open,
.release = userspace_buffer_release,
.read = userspace_buffer_read,
@@ -1452,7 +1304,7 @@ static const struct file_operations depth_fops = {
.write = depth_write
};
-void gator_op_create_files(struct super_block *sb, struct dentry *root)
+static void gator_op_create_files(struct super_block *sb, struct dentry *root)
{
struct dentry *dir;
struct gator_interface *gi;