gator: Version 5.20

Signed-off-by: Jon Medhurst <tixy@linaro.org>
This commit is contained in:
Jon Medhurst
2014-10-30 18:01:15 +00:00
parent e31266f780
commit 96b56157b3
142 changed files with 5872 additions and 3418 deletions

View File

@@ -24,8 +24,8 @@ config GATOR_MALI_4XXMP
bool "Mali-400MP or Mali-450MP"
select GATOR_WITH_MALI_SUPPORT
config GATOR_MALI_T6XX
bool "Mali-T604 or Mali-T658"
config GATOR_MALI_MIDGARD
bool "Mali-T60x, Mali-T62x, Mali-T72x or Mali-T76x"
select GATOR_WITH_MALI_SUPPORT
endchoice

View File

@@ -14,17 +14,16 @@ gator-y := gator_main.o \
gator_events_net.o \
gator_events_perf_pmu.o \
gator_events_sched.o \
gator_events_threads.o \
# Convert the old GATOR_WITH_MALI_SUPPORT to the new kernel flags
ifneq ($(GATOR_WITH_MALI_SUPPORT),)
CONFIG_GATOR_WITH_MALI_SUPPORT := y
ifeq ($(GATOR_WITH_MALI_SUPPORT),MALI_T6xx)
ifeq ($(GATOR_WITH_MALI_SUPPORT),MALI_MIDGARD)
CONFIG_GATOR_MALI_4XXMP := n
CONFIG_GATOR_MALI_T6XX := y
CONFIG_GATOR_MALI_MIDGARD := y
else
CONFIG_GATOR_MALI_4XXMP := y
CONFIG_GATOR_MALI_T6XX := n
CONFIG_GATOR_MALI_MIDGARD := n
endif
EXTRA_CFLAGS += -DMALI_SUPPORT=$(GATOR_WITH_MALI_SUPPORT)
ifneq ($(GATOR_MALI_INTERFACE_STYLE),)
@@ -33,10 +32,10 @@ ifneq ($(GATOR_WITH_MALI_SUPPORT),)
endif
ifeq ($(CONFIG_GATOR_WITH_MALI_SUPPORT),y)
ifeq ($(CONFIG_GATOR_MALI_T6XX),y)
gator-y += gator_events_mali_t6xx.o \
gator_events_mali_t6xx_hw.o
include $(src)/mali_t6xx.mk
ifeq ($(CONFIG_GATOR_MALI_MIDGARD),y)
gator-y += gator_events_mali_midgard.o \
gator_events_mali_midgard_hw.o
include $(src)/mali_midgard.mk
else
gator-y += gator_events_mali_4xx.o
endif
@@ -46,7 +45,7 @@ ifeq ($(CONFIG_GATOR_WITH_MALI_SUPPORT),y)
ccflags-y += -I$(CONFIG_GATOR_MALI_PATH)
endif
ccflags-$(CONFIG_GATOR_MALI_4XXMP) += -DMALI_SUPPORT=MALI_4xx
ccflags-$(CONFIG_GATOR_MALI_T6XX) += -DMALI_SUPPORT=MALI_T6xx
ccflags-$(CONFIG_GATOR_MALI_MIDGARD) += -DMALI_SUPPORT=MALI_MIDGARD
endif
# GATOR_TEST controls whether to include (=1) or exclude (=0) test code.
@@ -54,16 +53,15 @@ GATOR_TEST ?= 0
EXTRA_CFLAGS += -DGATOR_TEST=$(GATOR_TEST)
# Should the original or new block_rq_complete API be used?
OLD_BLOCK_RQ_COMPLETE := $(shell grep -A3 block_rq_complete include/trace/events/block.h | grep nr_bytes > /dev/null; echo $$?)
OLD_BLOCK_RQ_COMPLETE := $(shell grep -A3 block_rq_complete $(srctree)/include/trace/events/block.h | grep nr_bytes -q; echo $$?)
EXTRA_CFLAGS += -DOLD_BLOCK_RQ_COMPLETE=$(OLD_BLOCK_RQ_COMPLETE)
gator-$(CONFIG_ARM) += gator_events_armv6.o \
gator_events_armv7.o \
gator_events_ccn-504.o \
gator_events_l2c-310.o \
gator_events_scorpion.o
gator-$(CONFIG_ARM64) += gator_events_ccn-504.o
gator-$(CONFIG_ARM64) +=
else

View File

@@ -14,13 +14,13 @@
#include <linux/mm.h>
#include <linux/list.h>
#define GATOR_PERF_SUPPORT LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
#define GATOR_PERF_PMU_SUPPORT GATOR_PERF_SUPPORT && defined(CONFIG_PERF_EVENTS) && (!(defined(__arm__) || defined(__aarch64__)) || defined(CONFIG_HW_PERF_EVENTS))
#define GATOR_PERF_SUPPORT (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
#define GATOR_PERF_PMU_SUPPORT (GATOR_PERF_SUPPORT && defined(CONFIG_PERF_EVENTS) && (!(defined(__arm__) || defined(__aarch64__)) || defined(CONFIG_HW_PERF_EVENTS)))
#define GATOR_NO_PERF_SUPPORT (!(GATOR_PERF_SUPPORT))
#define GATOR_CPU_FREQ_SUPPORT (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) && defined(CONFIG_CPU_FREQ)
#define GATOR_CPU_FREQ_SUPPORT ((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) && defined(CONFIG_CPU_FREQ))
#define GATOR_IKS_SUPPORT defined(CONFIG_BL_SWITCHER)
// cpu ids
/* cpu ids */
#define ARM1136 0xb36
#define ARM1156 0xb56
#define ARM1176 0xb76
@@ -29,7 +29,6 @@
#define CORTEX_A7 0xc07
#define CORTEX_A8 0xc08
#define CORTEX_A9 0xc09
#define CORTEX_A12 0xc0d
#define CORTEX_A15 0xc0f
#define CORTEX_A17 0xc0e
#define SCORPION 0x00f
@@ -42,20 +41,20 @@
#define AARCH64 0xd0f
#define OTHER 0xfff
// gpu enums
/* gpu enums */
#define MALI_4xx 1
#define MALI_T6xx 2
#define MALI_MIDGARD 2
#define MAXSIZE_CORE_NAME 32
struct gator_cpu {
const int cpuid;
// Human readable name
/* Human readable name */
const char core_name[MAXSIZE_CORE_NAME];
// gatorfs event and Perf PMU name
const char * const pmnc_name;
// compatible from Documentation/devicetree/bindings/arm/cpus.txt
const char * const dt_name;
/* gatorfs event and Perf PMU name */
const char *const pmnc_name;
/* compatible from Documentation/devicetree/bindings/arm/cpus.txt */
const char *const dt_name;
const int pmnc_counters;
};
@@ -98,7 +97,7 @@ int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
extern struct tracepoint *gator_tracepoint_##probe_name; \
static void probe_##probe_name(void *data, PARAMS(proto))
# define GATOR_REGISTER_TRACE(probe_name) \
tracepoint_probe_register(gator_tracepoint_##probe_name, probe_##probe_name, NULL)
((gator_tracepoint_##probe_name == NULL) || tracepoint_probe_register(gator_tracepoint_##probe_name, probe_##probe_name, NULL))
# define GATOR_UNREGISTER_TRACE(probe_name) \
tracepoint_probe_unregister(gator_tracepoint_##probe_name, probe_##probe_name, NULL)
#endif
@@ -107,15 +106,19 @@ int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
* Events
******************************************************************************/
struct gator_interface {
void (*shutdown)(void); // Complementary function to init
/* Complementary function to init */
void (*shutdown)(void);
int (*create_files)(struct super_block *sb, struct dentry *root);
int (*start)(void);
void (*stop)(void); // Complementary function to start
/* Complementary function to start */
void (*stop)(void);
int (*online)(int **buffer, bool migrate);
int (*offline)(int **buffer, bool migrate);
void (*online_dispatch)(int cpu, bool migrate); // called in process context but may not be running on core 'cpu'
void (*offline_dispatch)(int cpu, bool migrate); // called in process context but may not be running on core 'cpu'
int (*read)(int **buffer);
/* called in process context but may not be running on core 'cpu' */
void (*online_dispatch)(int cpu, bool migrate);
/* called in process context but may not be running on core 'cpu' */
void (*offline_dispatch)(int cpu, bool migrate);
int (*read)(int **buffer, bool sched_switch);
int (*read64)(long long **buffer);
int (*read_proc)(long long **buffer, struct task_struct *);
struct list_head list;
@@ -146,4 +149,4 @@ int pcpu_to_lcpu(const int pcpu);
#define get_logical_cpu() smp_processor_id()
#define on_primary_core() (get_logical_cpu() == 0)
#endif // GATOR_H_
#endif /* GATOR_H_ */

View File

@@ -11,12 +11,12 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#include <asm/current.h>
#include <linux/spinlock.h>
static DEFINE_SPINLOCK(annotate_lock);
static bool collect_annotations = false;
static bool collect_annotations;
static int annotate_copy(struct file *file, char const __user *buf, size_t count)
{
@@ -24,10 +24,10 @@ static int annotate_copy(struct file *file, char const __user *buf, size_t count
int write = per_cpu(gator_buffer_write, cpu)[ANNOTATE_BUF];
if (file == NULL) {
// copy from kernel
/* copy from kernel */
memcpy(&per_cpu(gator_buffer, cpu)[ANNOTATE_BUF][write], buf, count);
} else {
// copy from user space
/* copy from user space */
if (copy_from_user(&per_cpu(gator_buffer, cpu)[ANNOTATE_BUF][write], buf, count) != 0)
return -1;
}
@@ -41,70 +41,70 @@ static ssize_t annotate_write(struct file *file, char const __user *buf, size_t
int pid, cpu, header_size, available, contiguous, length1, length2, size, count = count_orig & 0x7fffffff;
bool interrupt_context;
if (*offset) {
if (*offset)
return -EINVAL;
}
interrupt_context = in_interrupt();
// Annotations are not supported in interrupt context, but may work if you comment out the the next four lines of code.
// By doing so, annotations in interrupt context can result in deadlocks and lost data.
/* Annotations are not supported in interrupt context, but may work
* if you comment out the the next four lines of code. By doing so,
* annotations in interrupt context can result in deadlocks and lost
* data.
*/
if (interrupt_context) {
printk(KERN_WARNING "gator: Annotations are not supported in interrupt context. Edit gator_annotate.c in the gator driver to enable annotations in interrupt context.\n");
pr_warning("gator: Annotations are not supported in interrupt context. Edit gator_annotate.c in the gator driver to enable annotations in interrupt context.\n");
return -EINVAL;
}
retry:
// synchronize between cores and with collect_annotations
/* synchronize between cores and with collect_annotations */
spin_lock(&annotate_lock);
if (!collect_annotations) {
// Not collecting annotations, tell the caller everything was written
/* Not collecting annotations, tell the caller everything was written */
size = count_orig;
goto annotate_write_out;
}
// Annotation only uses a single per-cpu buffer as the data must be in order to the engine
/* Annotation only uses a single per-cpu buffer as the data must be in order to the engine */
cpu = 0;
if (current == NULL) {
if (current == NULL)
pid = 0;
} else {
else
pid = current->pid;
}
// determine total size of the payload
/* determine total size of the payload */
header_size = MAXSIZE_PACK32 * 3 + MAXSIZE_PACK64;
available = buffer_bytes_available(cpu, ANNOTATE_BUF) - header_size;
size = count < available ? count : available;
if (size <= 0) {
// Buffer is full, wait until space is available
/* Buffer is full, wait until space is available */
spin_unlock(&annotate_lock);
// Drop the annotation as blocking is not allowed in interrupt context
if (interrupt_context) {
/* Drop the annotation as blocking is not allowed in interrupt context */
if (interrupt_context)
return -EINVAL;
}
wait_event_interruptible(gator_annotate_wait, buffer_bytes_available(cpu, ANNOTATE_BUF) > header_size || !collect_annotations);
// Check to see if a signal is pending
if (signal_pending(current)) {
/* Check to see if a signal is pending */
if (signal_pending(current))
return -EINTR;
}
goto retry;
}
// synchronize shared variables annotateBuf and annotatePos
/* synchronize shared variables annotateBuf and annotatePos */
if (per_cpu(gator_buffer, cpu)[ANNOTATE_BUF]) {
u64 time = gator_get_time();
gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, get_physical_cpu());
gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, pid);
gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, time);
gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, size);
// determine the sizes to capture, length1 + length2 will equal size
/* determine the sizes to capture, length1 + length2 will equal size */
contiguous = contiguous_space_available(cpu, ANNOTATE_BUF);
if (size < contiguous) {
length1 = size;
@@ -124,14 +124,14 @@ static ssize_t annotate_write(struct file *file, char const __user *buf, size_t
goto annotate_write_out;
}
// Check and commit; commit is set to occur once buffer is 3/4 full
/* Check and commit; commit is set to occur once buffer is 3/4 full */
buffer_check(cpu, ANNOTATE_BUF, time);
}
annotate_write_out:
spin_unlock(&annotate_lock);
// return the number of bytes written
/* return the number of bytes written */
return size;
}
@@ -141,18 +141,21 @@ static int annotate_release(struct inode *inode, struct file *file)
{
int cpu = 0;
// synchronize between cores
/* synchronize between cores */
spin_lock(&annotate_lock);
if (per_cpu(gator_buffer, cpu)[ANNOTATE_BUF] && buffer_check_space(cpu, ANNOTATE_BUF, MAXSIZE_PACK64 + 3 * MAXSIZE_PACK32)) {
uint32_t pid = current->pid;
gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, get_physical_cpu());
gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, pid);
gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, 0); // time
gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, 0); // size
/* time */
gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, 0);
/* size */
gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, 0);
}
// Check and commit; commit is set to occur once buffer is 3/4 full
/* Check and commit; commit is set to occur once buffer is 3/4 full */
buffer_check(cpu, ANNOTATE_BUF, gator_get_time());
spin_unlock(&annotate_lock);
@@ -178,7 +181,7 @@ static int gator_annotate_start(void)
static void gator_annotate_stop(void)
{
// the spinlock here will ensure that when this function exits, we are not in the middle of an annotation
/* the spinlock here will ensure that when this function exits, we are not in the middle of an annotation */
spin_lock(&annotate_lock);
collect_annotations = false;
wake_up(&gator_annotate_wait);

View File

@@ -19,10 +19,11 @@ static void kannotate_write(const char *ptr, unsigned int size)
int retval;
int pos = 0;
loff_t offset = 0;
while (pos < size) {
retval = annotate_write(NULL, &ptr[pos], size - pos, &offset);
if (retval < 0) {
printk(KERN_WARNING "gator: kannotate_write failed with return value %d\n", retval);
pr_warning("gator: kannotate_write failed with return value %d\n", retval);
return;
}
pos += retval;
@@ -47,6 +48,7 @@ void gator_annotate_channel(int channel, const char *str)
{
const u16 str_size = strlen(str) & 0xffff;
char header[8];
header[0] = ESCAPE_CODE;
header[1] = STRING_ANNOTATION;
marshal_u32(header + 2, channel);
@@ -54,20 +56,19 @@ void gator_annotate_channel(int channel, const char *str)
kannotate_write(header, sizeof(header));
kannotate_write(str, str_size);
}
EXPORT_SYMBOL(gator_annotate_channel);
void gator_annotate(const char *str)
{
gator_annotate_channel(0, str);
}
EXPORT_SYMBOL(gator_annotate);
void gator_annotate_channel_color(int channel, int color, const char *str)
{
const u16 str_size = (strlen(str) + 4) & 0xffff;
char header[12];
header[0] = ESCAPE_CODE;
header[1] = STRING_ANNOTATION;
marshal_u32(header + 2, channel);
@@ -76,39 +77,37 @@ void gator_annotate_channel_color(int channel, int color, const char *str)
kannotate_write(header, sizeof(header));
kannotate_write(str, str_size - 4);
}
EXPORT_SYMBOL(gator_annotate_channel_color);
void gator_annotate_color(int color, const char *str)
{
gator_annotate_channel_color(0, color, str);
}
EXPORT_SYMBOL(gator_annotate_color);
void gator_annotate_channel_end(int channel)
{
char header[8];
header[0] = ESCAPE_CODE;
header[1] = STRING_ANNOTATION;
marshal_u32(header + 2, channel);
marshal_u16(header + 6, 0);
kannotate_write(header, sizeof(header));
}
EXPORT_SYMBOL(gator_annotate_channel_end);
void gator_annotate_end(void)
{
gator_annotate_channel_end(0);
}
EXPORT_SYMBOL(gator_annotate_end);
void gator_annotate_name_channel(int channel, int group, const char* str)
void gator_annotate_name_channel(int channel, int group, const char *str)
{
const u16 str_size = strlen(str) & 0xffff;
char header[12];
header[0] = ESCAPE_CODE;
header[1] = NAME_CHANNEL_ANNOTATION;
marshal_u32(header + 2, channel);
@@ -117,13 +116,13 @@ void gator_annotate_name_channel(int channel, int group, const char* str)
kannotate_write(header, sizeof(header));
kannotate_write(str, str_size);
}
EXPORT_SYMBOL(gator_annotate_name_channel);
void gator_annotate_name_group(int group, const char* str)
void gator_annotate_name_group(int group, const char *str)
{
const u16 str_size = strlen(str) & 0xffff;
char header[8];
header[0] = ESCAPE_CODE;
header[1] = NAME_GROUP_ANNOTATION;
marshal_u32(header + 2, group);
@@ -131,7 +130,6 @@ void gator_annotate_name_group(int group, const char* str)
kannotate_write(header, sizeof(header));
kannotate_write(str, str_size);
}
EXPORT_SYMBOL(gator_annotate_name_group);
void gator_annotate_visual(const char *data, unsigned int length, const char *str)
@@ -139,6 +137,7 @@ void gator_annotate_visual(const char *data, unsigned int length, const char *st
const u16 str_size = strlen(str) & 0xffff;
char header[4];
char header_length[4];
header[0] = ESCAPE_CODE;
header[1] = VISUAL_ANNOTATION;
marshal_u16(header + 2, str_size);
@@ -148,49 +147,49 @@ void gator_annotate_visual(const char *data, unsigned int length, const char *st
kannotate_write(header_length, sizeof(header_length));
kannotate_write(data, length);
}
EXPORT_SYMBOL(gator_annotate_visual);
void gator_annotate_marker(void)
{
char header[4];
header[0] = ESCAPE_CODE;
header[1] = MARKER_ANNOTATION;
marshal_u16(header + 2, 0);
kannotate_write(header, sizeof(header));
}
EXPORT_SYMBOL(gator_annotate_marker);
void gator_annotate_marker_str(const char *str)
{
const u16 str_size = strlen(str) & 0xffff;
char header[4];
header[0] = ESCAPE_CODE;
header[1] = MARKER_ANNOTATION;
marshal_u16(header + 2, str_size);
kannotate_write(header, sizeof(header));
kannotate_write(str, str_size);
}
EXPORT_SYMBOL(gator_annotate_marker_str);
void gator_annotate_marker_color(int color)
{
char header[8];
header[0] = ESCAPE_CODE;
header[1] = MARKER_ANNOTATION;
marshal_u16(header + 2, 4);
marshal_u32(header + 4, color);
kannotate_write(header, sizeof(header));
}
EXPORT_SYMBOL(gator_annotate_marker_color);
void gator_annotate_marker_color_str(int color, const char *str)
{
const u16 str_size = (strlen(str) + 4) & 0xffff;
char header[8];
header[0] = ESCAPE_CODE;
header[1] = MARKER_ANNOTATION;
marshal_u16(header + 2, str_size);
@@ -198,5 +197,4 @@ void gator_annotate_marker_color_str(int color, const char *str)
kannotate_write(header, sizeof(header));
kannotate_write(str, str_size - 4);
}
EXPORT_SYMBOL(gator_annotate_marker_color_str);

View File

@@ -14,17 +14,17 @@ struct stack_frame_eabi {
union {
struct {
unsigned long fp;
// May be the fp in the case of a leaf function or clang
/* May be the fp in the case of a leaf function or clang */
unsigned long lr;
// If lr is really the fp, lr2 is the corresponding lr
/* If lr is really the fp, lr2 is the corresponding lr */
unsigned long lr2;
};
// Used to read 32 bit fp/lr from a 64 bit kernel
/* Used to read 32 bit fp/lr from a 64 bit kernel */
struct {
u32 fp_32;
// same as lr above
/* same as lr above */
u32 lr_32;
// same as lr2 above
/* same as lr2 above */
u32 lr2_32;
};
};
@@ -35,9 +35,8 @@ 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) {
if (cookie == NO_COOKIE || cookie == UNRESOLVED_COOKIE)
offset = address;
}
marshal_backtrace(offset & ~1, cookie, 0);
}
@@ -54,36 +53,34 @@ static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int
unsigned long lr = regs->ARM_lr;
const int gcc_frame_offset = sizeof(unsigned long);
#else
// Is userspace aarch32 (32 bit)
/* Is userspace aarch32 (32 bit) */
const bool is_compat = compat_user_mode(regs);
unsigned long fp = (is_compat ? regs->regs[11] : regs->regs[29]);
unsigned long sp = (is_compat ? regs->compat_sp : regs->sp);
unsigned long lr = (is_compat ? regs->compat_lr : regs->regs[30]);
const int gcc_frame_offset = (is_compat ? sizeof(u32) : 0);
#endif
// clang frame offset is always zero
/* clang frame offset is always zero */
int is_user_mode = user_mode(regs);
// pc (current function) has already been added
/* pc (current function) has already been added */
if (!is_user_mode) {
if (!is_user_mode)
return;
}
// Add the lr (parent function)
// entry preamble may not have executed
/* Add the lr (parent function), entry preamble may not have
* executed
*/
gator_add_trace(cpu, lr);
// check fp is valid
if (fp == 0 || fp < sp) {
/* check fp is valid */
if (fp == 0 || fp < sp)
return;
}
// Get the current stack frame
/* Get the current stack frame */
curr = (struct stack_frame_eabi *)(fp - gcc_frame_offset);
if ((unsigned long)curr & 3) {
if ((unsigned long)curr & 3)
return;
}
while (depth-- && curr) {
if (!access_ok(VERIFY_READ, curr, sizeof(struct stack_frame_eabi)) ||
@@ -95,13 +92,15 @@ static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int
lr = (is_compat ? bufcurr.lr_32 : bufcurr.lr);
#define calc_next(reg) ((reg) - gcc_frame_offset)
// Returns true if reg is a valid fp
/* Returns true if reg is a valid fp */
#define validate_next(reg, curr) \
((reg) != 0 && (calc_next(reg) & 3) == 0 && (unsigned long)(curr) < calc_next(reg))
// Try lr from the stack as the fp because gcc leaf functions do not push lr
// If gcc_frame_offset is non-zero, the lr will also be the clang fp
// This assumes code is at a lower address than the stack
/* Try lr from the stack as the fp because gcc leaf functions do
* not push lr. If gcc_frame_offset is non-zero, the lr will also
* be the clang fp. This assumes code is at a lower address than
* the stack
*/
if (validate_next(lr, curr)) {
fp = lr;
lr = (is_compat ? bufcurr.lr2_32 : bufcurr.lr2);
@@ -109,11 +108,10 @@ static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int
gator_add_trace(cpu, lr);
if (!validate_next(fp, curr)) {
if (!validate_next(fp, curr))
return;
}
// Move to the next stack frame
/* Move to the next stack frame */
curr = (struct stack_frame_eabi *)calc_next(fp);
}
#endif
@@ -129,6 +127,7 @@ static int report_trace(struct stackframe *frame, void *d)
#if defined(MODULE)
unsigned int cpu = get_physical_cpu();
struct module *mod = __module_address(addr);
if (mod) {
cookie = get_cookie(cpu, current, mod->name, false);
addr = addr - (unsigned long)mod->module_core;
@@ -142,13 +141,13 @@ static int report_trace(struct stackframe *frame, void *d)
}
#endif
// Uncomment the following line to enable kernel stack unwinding within gator, note it can also be defined from the Makefile
// #define GATOR_KERNEL_STACK_UNWINDING
/* Uncomment the following line to enable kernel stack unwinding within gator, note it can also be defined from the Makefile */
/* #define GATOR_KERNEL_STACK_UNWINDING */
#if (defined(__arm__) || defined(__aarch64__)) && !defined(GATOR_KERNEL_STACK_UNWINDING)
// Disabled by default
/* Disabled by default */
MODULE_PARM_DESC(kernel_stack_unwinding, "Allow kernel stack unwinding.");
static bool kernel_stack_unwinding = 0;
static bool kernel_stack_unwinding;
module_param(kernel_stack_unwinding, bool, 0644);
#endif
@@ -161,6 +160,7 @@ static void kernel_backtrace(int cpu, struct pt_regs *const regs)
int depth = (kernel_stack_unwinding ? gator_backtrace_depth : 1);
#endif
struct stackframe frame;
if (depth == 0)
depth = 1;
#if defined(__arm__)
@@ -196,10 +196,10 @@ static void gator_add_sample(int cpu, struct pt_regs *const regs, u64 time)
if (in_kernel) {
kernel_backtrace(cpu, regs);
} else {
// Cookie+PC
/* Cookie+PC */
gator_add_trace(cpu, PC_REG);
// Backtrace
/* Backtrace */
if (gator_backtrace_depth)
arm_backtrace_eabi(cpu, regs, gator_backtrace_depth);
}

View File

@@ -10,55 +10,65 @@
static void marshal_frame(int cpu, int buftype)
{
int frame;
bool write_cpu;
if (!per_cpu(gator_buffer, cpu)[buftype]) {
if (!per_cpu(gator_buffer, cpu)[buftype])
return;
}
switch (buftype) {
case SUMMARY_BUF:
write_cpu = false;
frame = FRAME_SUMMARY;
break;
case BACKTRACE_BUF:
write_cpu = true;
frame = FRAME_BACKTRACE;
break;
case NAME_BUF:
write_cpu = true;
frame = FRAME_NAME;
break;
case COUNTER_BUF:
write_cpu = false;
frame = FRAME_COUNTER;
break;
case BLOCK_COUNTER_BUF:
write_cpu = true;
frame = FRAME_BLOCK_COUNTER;
break;
case ANNOTATE_BUF:
write_cpu = false;
frame = FRAME_ANNOTATE;
break;
case SCHED_TRACE_BUF:
write_cpu = true;
frame = FRAME_SCHED_TRACE;
break;
case IDLE_BUF:
write_cpu = false;
frame = FRAME_IDLE;
break;
case ACTIVITY_BUF:
write_cpu = false;
frame = FRAME_ACTIVITY;
break;
default:
write_cpu = false;
frame = -1;
break;
}
// add response type
if (gator_response_type > 0) {
/* add response type */
if (gator_response_type > 0)
gator_buffer_write_packed_int(cpu, buftype, gator_response_type);
}
// leave space for 4-byte unpacked length
/* leave space for 4-byte unpacked length */
per_cpu(gator_buffer_write, cpu)[buftype] = (per_cpu(gator_buffer_write, cpu)[buftype] + sizeof(s32)) & gator_buffer_mask[buftype];
// add frame type and core number
/* add frame type and core number */
gator_buffer_write_packed_int(cpu, buftype, frame);
gator_buffer_write_packed_int(cpu, buftype, cpu);
if (write_cpu)
gator_buffer_write_packed_int(cpu, buftype, cpu);
}
static int buffer_bytes_available(int cpu, int buftype)
@@ -66,19 +76,17 @@ 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) {
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
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
else
/* Hysteresis, prevents multiple overflow messages */
remaining -= 2000;
}
return remaining;
}
@@ -87,11 +95,10 @@ static bool buffer_check_space(int cpu, int buftype, int bytes)
{
int remaining = buffer_bytes_available(cpu, buftype);
if (remaining < bytes) {
if (remaining < bytes)
per_cpu(buffer_space_available, cpu)[buftype] = false;
} else {
else
per_cpu(buffer_space_available, cpu)[buftype] = true;
}
return per_cpu(buffer_space_available, cpu)[buftype];
}
@@ -100,10 +107,10 @@ 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;
return contiguous;
}
static void gator_commit_buffer(int cpu, int buftype, u64 time)
@@ -114,41 +121,38 @@ static void gator_commit_buffer(int cpu, int buftype, u64 time)
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
/* post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload */
local_irq_save(flags);
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) {
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
/* Nothing to write, only the frame header is present */
local_irq_restore(flags);
return;
}
for (byte = 0; byte < sizeof(s32); byte++) {
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)) {
while (time > per_cpu(gator_buffer_commit_time, cpu))
per_cpu(gator_buffer_commit_time, cpu) += gator_live_rate;
}
}
marshal_frame(cpu, buftype);
local_irq_restore(flags);
// had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
/* 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 can not be used in interrupt context in RT-Preempt full */
mod_timer(&gator_buffer_wake_up_timer, jiffies + 1);
#endif
} else {
@@ -159,10 +163,9 @@ static void gator_commit_buffer(int cpu, int buftype, u64 time)
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) {
if (filled < 0)
filled += gator_buffer_size[buftype];
}
if (filled >= ((gator_buffer_size[buftype] * 3) / 4)) {
if (filled >= ((gator_buffer_size[buftype] * 3) / 4))
gator_commit_buffer(cpu, buftype, time);
}
}

View File

@@ -14,16 +14,17 @@ static void gator_buffer_write_packed_int(int cpu, int buftype, int x)
char *buffer = per_cpu(gator_buffer, cpu)[buftype];
int packedBytes = 0;
int more = true;
while (more) {
// low order 7 bits of x
/* low order 7 bits of x */
char b = x & 0x7f;
x >>= 7;
if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0))
more = false;
} else {
else
b |= 0x80;
}
buffer[(write + packedBytes) & mask] = b;
packedBytes++;
@@ -39,16 +40,17 @@ static void gator_buffer_write_packed_int64(int cpu, int buftype, long long x)
char *buffer = per_cpu(gator_buffer, cpu)[buftype];
int packedBytes = 0;
int more = true;
while (more) {
// low order 7 bits of x
/* low order 7 bits of x */
char b = x & 0x7f;
x >>= 7;
if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0))
more = false;
} else {
else
b |= 0x80;
}
buffer[(write + packedBytes) & mask] = b;
packedBytes++;
@@ -75,6 +77,7 @@ static void gator_buffer_write_bytes(int cpu, int buftype, const char *x, int le
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);
}

View File

@@ -7,8 +7,10 @@
*
*/
#define COOKIEMAP_ENTRIES 1024 /* must be power of 2 */
#define TRANSLATE_BUFFER_SIZE 512 // must be a power of 2 - 512/4 = 128 entries
/* must be power of 2 */
#define COOKIEMAP_ENTRIES 1024
/* must be a power of 2 - 512/4 = 128 entries */
#define TRANSLATE_BUFFER_SIZE 512
#define TRANSLATE_TEXT_SIZE 256
#define MAX_COLLISIONS 2
@@ -38,6 +40,7 @@ static uint32_t cookiemap_code(uint64_t value64)
{
uint32_t value = (uint32_t)((value64 >> 32) + value64);
uint32_t cookiecode = (value >> 24) & 0xff;
cookiecode = cookiecode * 31 + ((value >> 16) & 0xff);
cookiecode = cookiecode * 31 + ((value >> 8) & 0xff);
cookiecode = cookiecode * 31 + ((value >> 0) & 0xff);
@@ -52,9 +55,8 @@ static uint32_t gator_chksum_crc32(const char *data)
int i, length = strlen(data);
crc = 0xFFFFFFFF;
for (i = 0; i < length; i++) {
for (i = 0; i < length; i++)
crc = ((crc >> 8) & 0x00FFFFFF) ^ gator_crc32_table[(crc ^ *block++) & 0xFF];
}
return (crc ^ 0xFFFFFFFF);
}
@@ -72,11 +74,12 @@ static uint32_t cookiemap_exists(uint64_t key)
uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]);
uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]);
// Can be called from interrupt handler or from work queue
/* Can be called from interrupt handler or from work queue */
local_irq_save(flags);
for (x = 0; x < MAX_COLLISIONS; x++) {
if (keys[x] == key) {
uint32_t value = values[x];
for (; x > 0; x--) {
keys[x] = keys[x - 1];
values[x] = values[x - 1];
@@ -126,7 +129,7 @@ static void translate_buffer_write_args(int cpu, struct task_struct *task, const
write = per_cpu(translate_buffer_write, cpu);
next_write = (write + 1) & translate_buffer_mask;
// At least one entry must always remain available as when read == write, the queue is empty not full
/* At least one entry must always remain available as when read == write, the queue is empty not full */
if (next_write != per_cpu(translate_buffer_read, cpu)) {
args = &per_cpu(translate_buffer, cpu)[write];
args->task = task;
@@ -178,11 +181,11 @@ static void wq_cookie_handler(struct work_struct *unused)
static void app_process_wake_up_handler(unsigned long unused_data)
{
// had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
/* had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater */
schedule_work(&cookie_work);
}
// Retrieve full name from proc/pid/cmdline for java processes on Android
/* Retrieve full name from proc/pid/cmdline for java processes on Android */
static int translate_app_process(const char **text, int cpu, struct task_struct *task, bool from_wq)
{
void *maddr;
@@ -195,12 +198,16 @@ static int translate_app_process(const char **text, int cpu, struct task_struct
char *buf = per_cpu(translate_text, cpu);
#ifndef CONFIG_PREEMPT_RT_FULL
// Push work into a work queue if in atomic context as the kernel functions below might sleep
// Rely on the in_interrupt variable rather than in_irq() or in_interrupt() kernel functions, as the value of these functions seems
// inconsistent during a context switch between android/linux versions
/* Push work into a work queue if in atomic context as the kernel
* functions below might sleep. Rely on the in_interrupt variable
* rather than in_irq() or in_interrupt() kernel functions, as the
* value of these functions seems inconsistent during a context
* switch between android/linux versions
*/
if (!from_wq) {
// Check if already in buffer
/* Check if already in buffer */
int pos = per_cpu(translate_buffer_read, cpu);
while (pos != per_cpu(translate_buffer_write, cpu)) {
if (per_cpu(translate_buffer, cpu)[pos].task == task)
goto out;
@@ -209,7 +216,7 @@ static int translate_app_process(const char **text, int cpu, struct task_struct
translate_buffer_write_args(cpu, task, *text);
// Not safe to call in RT-Preempt full in schedule switch context
/* Not safe to call in RT-Preempt full in schedule switch context */
mod_timer(&app_process_wake_up_timer, jiffies + 1);
goto out;
}
@@ -239,7 +246,8 @@ static int translate_app_process(const char **text, int cpu, struct task_struct
copy_from_user_page(page_vma, page, addr, buf, maddr + offset, bytes);
kunmap(page); // release page allocated by get_user_pages()
/* release page allocated by get_user_pages() */
kunmap(page);
page_cache_release(page);
len -= bytes;
@@ -250,7 +258,7 @@ static int translate_app_process(const char **text, int cpu, struct task_struct
retval = 1;
}
// On app_process startup, /proc/pid/cmdline is initially "zygote" then "<pre-initialized>" but changes after an initial startup period
/* On app_process startup, /proc/pid/cmdline is initially "zygote" then "<pre-initialized>" but changes after an initial startup period */
if (strcmp(*text, "zygote") == 0 || strcmp(*text, "<pre-initialized>") == 0)
retval = 0;
@@ -262,6 +270,8 @@ out:
return retval;
}
static const char APP_PROCESS[] = "app_process";
static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq)
{
unsigned long flags, cookie;
@@ -271,16 +281,16 @@ static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text,
key = (key << 32) | (uint32_t)task->tgid;
cookie = cookiemap_exists(key);
if (cookie) {
if (cookie)
return cookie;
}
if (strcmp(text, "app_process") == 0) {
/* On 64-bit android app_process can be app_process32 or app_process64 */
if (strncmp(text, APP_PROCESS, sizeof(APP_PROCESS) - 1) == 0) {
if (!translate_app_process(&text, cpu, task, from_wq))
return UNRESOLVED_COOKIE;
}
// Can be called from interrupt handler or from work queue or from scheduler trace
/* Can be called from interrupt handler or from work queue or from scheduler trace */
local_irq_save(flags);
cookie = UNRESOLVED_COOKIE;
@@ -300,7 +310,7 @@ static int get_exec_cookie(int cpu, struct task_struct *task)
struct mm_struct *mm = task->mm;
const char *text;
// kernel threads have no address space
/* kernel threads have no address space */
if (!mm)
return NO_COOKIE;
@@ -355,7 +365,7 @@ static int cookies_initialize(void)
per_cpu(cookie_next_key, cpu) = nr_cpu_ids + cpu;
size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint64_t);
per_cpu(cookie_keys, cpu) = (uint64_t *)kmalloc(size, GFP_KERNEL);
per_cpu(cookie_keys, cpu) = kmalloc(size, GFP_KERNEL);
if (!per_cpu(cookie_keys, cpu)) {
err = -ENOMEM;
goto cookie_setup_error;
@@ -363,14 +373,14 @@ static int cookies_initialize(void)
memset(per_cpu(cookie_keys, cpu), 0, size);
size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint32_t);
per_cpu(cookie_values, cpu) = (uint32_t *)kmalloc(size, GFP_KERNEL);
per_cpu(cookie_values, cpu) = kmalloc(size, GFP_KERNEL);
if (!per_cpu(cookie_values, cpu)) {
err = -ENOMEM;
goto cookie_setup_error;
}
memset(per_cpu(cookie_values, cpu), 0, size);
per_cpu(translate_buffer, cpu) = (struct cookie_args *)kmalloc(TRANSLATE_BUFFER_SIZE, GFP_KERNEL);
per_cpu(translate_buffer, cpu) = kmalloc(TRANSLATE_BUFFER_SIZE, GFP_KERNEL);
if (!per_cpu(translate_buffer, cpu)) {
err = -ENOMEM;
goto cookie_setup_error;
@@ -379,16 +389,16 @@ static int cookies_initialize(void)
per_cpu(translate_buffer_write, cpu) = 0;
per_cpu(translate_buffer_read, cpu) = 0;
per_cpu(translate_text, cpu) = (char *)kmalloc(TRANSLATE_TEXT_SIZE, GFP_KERNEL);
per_cpu(translate_text, cpu) = kmalloc(TRANSLATE_TEXT_SIZE, GFP_KERNEL);
if (!per_cpu(translate_text, cpu)) {
err = -ENOMEM;
goto cookie_setup_error;
}
}
// build CRC32 table
/* build CRC32 table */
poly = 0x04c11db7;
gator_crc32_table = (uint32_t *)kmalloc(256 * sizeof(uint32_t), GFP_KERNEL);
gator_crc32_table = kmalloc(256 * sizeof(*gator_crc32_table), GFP_KERNEL);
if (!gator_crc32_table) {
err = -ENOMEM;
goto cookie_setup_error;
@@ -396,11 +406,10 @@ static int cookies_initialize(void)
for (i = 0; i < 256; i++) {
crc = i;
for (j = 8; j > 0; j--) {
if (crc & 1) {
if (crc & 1)
crc = (crc >> 1) ^ poly;
} else {
else
crc >>= 1;
}
}
gator_crc32_table[i] = crc;
}

View File

@@ -8,7 +8,7 @@
#include "gator.h"
// gator_events_perf_pmu.c is used if perf is supported
/* gator_events_perf_pmu.c is used if perf is supported */
#if GATOR_NO_PERF_SUPPORT
static const char *pmnc_name;
@@ -28,7 +28,7 @@ static const char *pmnc_name;
#define CCNT 2
#define CNTMAX (CCNT+1)
static int pmnc_counters = 0;
static int pmnc_counters;
static unsigned long pmnc_enabled[CNTMAX];
static unsigned long pmnc_event[CNTMAX];
static unsigned long pmnc_key[CNTMAX];
@@ -45,6 +45,7 @@ static inline void armv6_pmnc_write(u32 val)
static inline u32 armv6_pmnc_read(void)
{
u32 val;
asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (val));
return val;
}
@@ -52,6 +53,7 @@ static inline u32 armv6_pmnc_read(void)
static void armv6_pmnc_reset_counter(unsigned int cnt)
{
u32 val = 0;
switch (cnt) {
case CCNT:
asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r" (val));
@@ -74,20 +76,18 @@ int gator_events_armv6_create_files(struct super_block *sb, struct dentry *root)
for (i = PMN0; i <= CCNT; i++) {
char buf[40];
if (i == CCNT) {
snprintf(buf, sizeof buf, "ARM_%s_ccnt", pmnc_name);
} else {
snprintf(buf, sizeof buf, "ARM_%s_cnt%d", pmnc_name, i);
}
if (i == CCNT)
snprintf(buf, sizeof(buf), "ARM_%s_ccnt", pmnc_name);
else
snprintf(buf, sizeof(buf), "ARM_%s_cnt%d", pmnc_name, i);
dir = gatorfs_mkdir(sb, root, buf);
if (!dir) {
if (!dir)
return -1;
}
gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
if (i != CCNT) {
if (i != CCNT)
gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
}
}
return 0;
@@ -98,9 +98,8 @@ static int gator_events_armv6_online(int **buffer, bool migrate)
unsigned int cnt, len = 0, cpu = smp_processor_id();
u32 pmnc;
if (armv6_pmnc_read() & PMCR_E) {
if (armv6_pmnc_read() & PMCR_E)
armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
}
/* initialize PMNC, reset overflow, D bit, C bit and P bit. */
armv6_pmnc_write(PMCR_OFL_PMN0 | PMCR_OFL_PMN1 | PMCR_OFL_CCNT |
@@ -115,19 +114,18 @@ static int gator_events_armv6_online(int **buffer, bool migrate)
event = pmnc_event[cnt] & 255;
// Set event (if destined for PMNx counters)
if (cnt == PMN0) {
/* Set event (if destined for PMNx counters) */
if (cnt == PMN0)
pmnc |= event << 20;
} else if (cnt == PMN1) {
else if (cnt == PMN1)
pmnc |= event << 12;
}
// Reset counter
/* Reset counter */
armv6_pmnc_reset_counter(cnt);
}
armv6_pmnc_write(pmnc | PMCR_E);
// return zero values, no need to read as the counters were just reset
/* return zero values, no need to read as the counters were just reset */
for (cnt = PMN0; cnt <= CCNT; cnt++) {
if (pmnc_enabled[cnt]) {
per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
@@ -146,9 +144,8 @@ static int gator_events_armv6_offline(int **buffer, bool migrate)
unsigned int cnt;
armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
for (cnt = PMN0; cnt <= CCNT; cnt++) {
for (cnt = PMN0; cnt <= CCNT; cnt++)
armv6_pmnc_reset_counter(cnt);
}
return 0;
}
@@ -163,19 +160,19 @@ static void gator_events_armv6_stop(void)
}
}
static int gator_events_armv6_read(int **buffer)
static int gator_events_armv6_read(int **buffer, bool sched_switch)
{
int cnt, len = 0;
int cpu = smp_processor_id();
// a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled
if (!(armv6_pmnc_read() & PMCR_E)) {
/* a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled */
if (!(armv6_pmnc_read() & PMCR_E))
return 0;
}
for (cnt = PMN0; cnt <= CCNT; cnt++) {
if (pmnc_enabled[cnt]) {
u32 value = 0;
switch (cnt) {
case CCNT:
asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r" (value));

View File

@@ -15,16 +15,16 @@
#include "gator.h"
// gator_events_perf_pmu.c is used if perf is supported
/* gator_events_perf_pmu.c is used if perf is supported */
#if GATOR_NO_PERF_SUPPORT
// Per-CPU PMNC: config reg
/* Per-CPU PMNC: config reg */
#define PMNC_E (1 << 0) /* Enable all counters */
#define PMNC_P (1 << 1) /* Reset all counters */
#define PMNC_C (1 << 2) /* Cycle counter reset */
#define PMNC_MASK 0x3f /* Mask for writable bits */
// ccnt reg
/* ccnt reg */
#define CCNT_REG (1 << 31)
#define CCNT 0
@@ -49,6 +49,7 @@ inline void armv7_pmnc_write(u32 val)
inline u32 armv7_pmnc_read(void)
{
u32 val;
asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
return val;
}
@@ -61,10 +62,10 @@ inline u32 armv7_ccnt_read(u32 reset_value)
u32 val;
local_irq_save(flags);
asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); // disable
asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); // read
asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (newval)); // new value
asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); // enable
asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); /* disable */
asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); /* read */
asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (newval)); /* new value */
asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); /* enable */
local_irq_restore(flags);
return val;
@@ -79,11 +80,11 @@ inline u32 armv7_cntn_read(unsigned int cnt, u32 reset_value)
u32 oldval;
local_irq_save(flags);
asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); // disable
asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (sel)); // select
asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (oldval)); // read
asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (newval)); // new value
asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); // enable
asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); /* disable */
asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (sel)); /* select */
asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (oldval)); /* read */
asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (newval)); /* new value */
asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); /* enable */
local_irq_restore(flags);
return oldval;
@@ -92,13 +93,15 @@ inline u32 armv7_cntn_read(unsigned int cnt, u32 reset_value)
static inline void armv7_pmnc_disable_interrupt(unsigned int cnt)
{
u32 val = cnt ? (1 << (cnt - CNT0)) : (1 << 31);
asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (val));
}
inline u32 armv7_pmnc_reset_interrupt(void)
{
// Get and reset overflow status flags
/* Get and reset overflow status flags */
u32 flags;
asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (flags));
flags &= 0x8000003f;
asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (flags));
@@ -108,6 +111,7 @@ inline u32 armv7_pmnc_reset_interrupt(void)
static inline u32 armv7_pmnc_enable_counter(unsigned int cnt)
{
u32 val = cnt ? (1 << (cnt - CNT0)) : CCNT_REG;
asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
return cnt;
}
@@ -115,6 +119,7 @@ static inline u32 armv7_pmnc_enable_counter(unsigned int cnt)
static inline u32 armv7_pmnc_disable_counter(unsigned int cnt)
{
u32 val = cnt ? (1 << (cnt - CNT0)) : CCNT_REG;
asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
return cnt;
}
@@ -122,15 +127,15 @@ static inline u32 armv7_pmnc_disable_counter(unsigned int cnt)
static inline int armv7_pmnc_select_counter(unsigned int cnt)
{
u32 val = (cnt - CNT0);
asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
return cnt;
}
static inline void armv7_pmnc_write_evtsel(unsigned int cnt, u32 val)
{
if (armv7_pmnc_select_counter(cnt) == cnt) {
if (armv7_pmnc_select_counter(cnt) == cnt)
asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
}
}
static int gator_events_armv7_create_files(struct super_block *sb, struct dentry *root)
@@ -140,20 +145,18 @@ static int gator_events_armv7_create_files(struct super_block *sb, struct dentry
for (i = 0; i < pmnc_counters; i++) {
char buf[40];
if (i == 0) {
snprintf(buf, sizeof buf, "%s_ccnt", pmnc_name);
} else {
snprintf(buf, sizeof buf, "%s_cnt%d", pmnc_name, i - 1);
}
if (i == 0)
snprintf(buf, sizeof(buf), "%s_ccnt", pmnc_name);
else
snprintf(buf, sizeof(buf), "%s_cnt%d", pmnc_name, i - 1);
dir = gatorfs_mkdir(sb, root, buf);
if (!dir) {
if (!dir)
return -1;
}
gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
if (i > 0) {
if (i > 0)
gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
}
}
return 0;
@@ -163,14 +166,13 @@ static int gator_events_armv7_online(int **buffer, bool migrate)
{
unsigned int cnt, len = 0, cpu = smp_processor_id();
if (armv7_pmnc_read() & PMNC_E) {
if (armv7_pmnc_read() & PMNC_E)
armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E);
}
// Initialize & Reset PMNC: C bit and P bit
/* Initialize & Reset PMNC: C bit and P bit */
armv7_pmnc_write(PMNC_P | PMNC_C);
// Reset overflow flags
/* Reset overflow flags */
armv7_pmnc_reset_interrupt();
for (cnt = CCNT; cnt < CNTMAX; cnt++) {
@@ -179,28 +181,28 @@ static int gator_events_armv7_online(int **buffer, bool migrate)
if (!pmnc_enabled[cnt])
continue;
// Disable counter
/* Disable counter */
armv7_pmnc_disable_counter(cnt);
event = pmnc_event[cnt] & 255;
// Set event (if destined for PMNx counters), we don't need to set the event if it's a cycle count
/* Set event (if destined for PMNx counters), we don't need to set the event if it's a cycle count */
if (cnt != CCNT)
armv7_pmnc_write_evtsel(cnt, event);
armv7_pmnc_disable_interrupt(cnt);
// Reset counter
/* Reset counter */
cnt ? armv7_cntn_read(cnt, 0) : armv7_ccnt_read(0);
// Enable counter
/* Enable counter */
armv7_pmnc_enable_counter(cnt);
}
// enable
/* enable */
armv7_pmnc_write(armv7_pmnc_read() | PMNC_E);
// return zero values, no need to read as the counters were just reset
/* return zero values, no need to read as the counters were just reset */
for (cnt = 0; cnt < pmnc_counters; cnt++) {
if (pmnc_enabled[cnt]) {
per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
@@ -216,7 +218,7 @@ static int gator_events_armv7_online(int **buffer, bool migrate)
static int gator_events_armv7_offline(int **buffer, bool migrate)
{
// disable all counters, including PMCCNTR; overflow IRQs will not be signaled
/* disable all counters, including PMCCNTR; overflow IRQs will not be signaled */
armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E);
return 0;
@@ -232,24 +234,23 @@ static void gator_events_armv7_stop(void)
}
}
static int gator_events_armv7_read(int **buffer)
static int gator_events_armv7_read(int **buffer, bool sched_switch)
{
int cnt, len = 0;
int cpu = smp_processor_id();
// a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled
if (!(armv7_pmnc_read() & PMNC_E)) {
/* a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled */
if (!(armv7_pmnc_read() & PMNC_E))
return 0;
}
for (cnt = 0; cnt < pmnc_counters; cnt++) {
if (pmnc_enabled[cnt]) {
int value;
if (cnt == CCNT) {
if (cnt == CCNT)
value = armv7_ccnt_read(0);
} else {
else
value = armv7_cntn_read(cnt, 0);
}
per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
per_cpu(perfCnt, cpu)[len++] = value;
}
@@ -290,17 +291,16 @@ int gator_events_armv7_init(void)
pmnc_name = "ARMv7_Cortex_A9";
pmnc_counters = 6;
break;
// ARM Cortex A12 is not supported by version of Linux before 3.0
case CORTEX_A15:
pmnc_name = "ARMv7_Cortex_A15";
pmnc_counters = 6;
break;
// ARM Cortex A17 is not supported by version of Linux before 3.0
/* ARM Cortex A17 is not supported by version of Linux before 3.0 */
default:
return -1;
}
pmnc_counters++; // CNT[n] + CCNT
pmnc_counters++; /* CNT[n] + CCNT */
for (cnt = CCNT; cnt < CNTMAX; cnt++) {
pmnc_enabled[cnt] = 0;

View File

@@ -28,7 +28,7 @@ static ulong block_rq_rd_key;
static atomic_t blockCnt[BLOCK_TOTAL];
static int blockGet[BLOCK_TOTAL * 4];
// Tracepoint changed in 3.15 backported to older kernels. The Makefile tries to autodetect the correct value, but if it fails change the #if below
/* Tracepoint changed in 3.15 backported to older kernels. The Makefile tries to autodetect the correct value, but if it fails change the #if below */
#if OLD_BLOCK_RQ_COMPLETE
GATOR_DEFINE_PROBE(block_rq_complete, TP_PROTO(struct request_queue *q, struct request *rq))
#else
@@ -52,13 +52,11 @@ GATOR_DEFINE_PROBE(block_rq_complete, TP_PROTO(struct request_queue *q, struct r
return;
if (write) {
if (block_rq_wr_enabled) {
if (block_rq_wr_enabled)
atomic_add(size, &blockCnt[BLOCK_RQ_WR]);
}
} else {
if (block_rq_rd_enabled) {
if (block_rq_rd_enabled)
atomic_add(size, &blockCnt[BLOCK_RQ_RD]);
}
}
}
@@ -68,17 +66,15 @@ static int gator_events_block_create_files(struct super_block *sb, struct dentry
/* block_complete_wr */
dir = gatorfs_mkdir(sb, root, "Linux_block_rq_wr");
if (!dir) {
if (!dir)
return -1;
}
gatorfs_create_ulong(sb, dir, "enabled", &block_rq_wr_enabled);
gatorfs_create_ro_ulong(sb, dir, "key", &block_rq_wr_key);
/* block_complete_rd */
dir = gatorfs_mkdir(sb, root, "Linux_block_rq_rd");
if (!dir) {
if (!dir)
return -1;
}
gatorfs_create_ulong(sb, dir, "enabled", &block_rq_rd_enabled);
gatorfs_create_ro_ulong(sb, dir, "key", &block_rq_rd_key);
@@ -87,7 +83,7 @@ static int gator_events_block_create_files(struct super_block *sb, struct dentry
static int gator_events_block_start(void)
{
// register tracepoints
/* register tracepoints */
if (block_rq_wr_enabled || block_rq_rd_enabled)
if (GATOR_REGISTER_TRACE(block_rq_complete))
goto fail_block_rq_exit;
@@ -95,7 +91,7 @@ static int gator_events_block_start(void)
return 0;
// unregister tracepoints on error
/* unregister tracepoints on error */
fail_block_rq_exit:
pr_err("gator: block event tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
@@ -112,19 +108,19 @@ static void gator_events_block_stop(void)
block_rq_rd_enabled = 0;
}
static int gator_events_block_read(int **buffer)
static int gator_events_block_read(int **buffer, bool sched_switch)
{
int len, value, data = 0;
if (!on_primary_core()) {
if (!on_primary_core())
return 0;
}
len = 0;
if (block_rq_wr_enabled && (value = atomic_read(&blockCnt[BLOCK_RQ_WR])) > 0) {
atomic_sub(value, &blockCnt[BLOCK_RQ_WR]);
blockGet[len++] = block_rq_wr_key;
blockGet[len++] = 0; // indicates to Streamline that value bytes were written now, not since the last message
/* Indicates to Streamline that value bytes were written now, not since the last message */
blockGet[len++] = 0;
blockGet[len++] = block_rq_wr_key;
blockGet[len++] = value;
data += value;
@@ -132,7 +128,8 @@ static int gator_events_block_read(int **buffer)
if (block_rq_rd_enabled && (value = atomic_read(&blockCnt[BLOCK_RQ_RD])) > 0) {
atomic_sub(value, &blockCnt[BLOCK_RQ_RD]);
blockGet[len++] = block_rq_rd_key;
blockGet[len++] = 0; // indicates to Streamline that value bytes were read now, not since the last message
/* Indicates to Streamline that value bytes were read now, not since the last message */
blockGet[len++] = 0;
blockGet[len++] = block_rq_rd_key;
blockGet[len++] = value;
data += value;

View File

@@ -1,346 +0,0 @@
/**
* Copyright (C) ARM Limited 2013-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
* published by the Free Software Foundation.
*/
#include <linux/io.h>
#include <linux/module.h>
#include "gator.h"
#define NUM_REGIONS 256
#define REGION_SIZE (64*1024)
#define REGION_DEBUG 1
#define REGION_XP 64
#define NUM_XPS 11
// DT (Debug) region
#define PMEVCNTSR0 0x0150
#define PMCCNTRSR 0x0190
#define PMCR 0x01A8
#define PMSR 0x01B0
#define PMSR_REQ 0x01B8
#define PMSR_CLR 0x01C0
// XP region
#define DT_CONFIG 0x0300
#define DT_CONTROL 0x0370
// Multiple
#define PMU_EVENT_SEL 0x0600
#define OLY_ID 0xFF00
#define CCNT 4
#define CNTMAX (CCNT + 1)
#define get_pmu_event_id(event) (((event) >> 0) & 0xFF)
#define get_node_type(event) (((event) >> 8) & 0xFF)
#define get_region(event) (((event) >> 16) & 0xFF)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
// From kernel/params.c
#define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn) \
int param_set_##name(const char *val, struct kernel_param *kp) \
{ \
tmptype l; \
int ret; \
\
if (!val) return -EINVAL; \
ret = strtolfn(val, 0, &l); \
if (ret == -EINVAL || ((type)l != l)) \
return -EINVAL; \
*((type *)kp->arg) = l; \
return 0; \
} \
int param_get_##name(char *buffer, struct kernel_param *kp) \
{ \
return sprintf(buffer, format, *((type *)kp->arg)); \
}
#else
// From kernel/params.c
#define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn) \
int param_set_##name(const char *val, const struct kernel_param *kp) \
{ \
tmptype l; \
int ret; \
\
ret = strtolfn(val, 0, &l); \
if (ret < 0 || ((type)l != l)) \
return ret < 0 ? ret : -EINVAL; \
*((type *)kp->arg) = l; \
return 0; \
} \
int param_get_##name(char *buffer, const struct kernel_param *kp) \
{ \
return scnprintf(buffer, PAGE_SIZE, format, \
*((type *)kp->arg)); \
} \
struct kernel_param_ops param_ops_##name = { \
.set = param_set_##name, \
.get = param_get_##name, \
}; \
EXPORT_SYMBOL(param_set_##name); \
EXPORT_SYMBOL(param_get_##name); \
EXPORT_SYMBOL(param_ops_##name)
#endif
STANDARD_PARAM_DEF(u64, u64, "%llu", u64, strict_strtoull);
// From include/linux/moduleparam.h
#define param_check_u64(name, p) __param_check(name, p, u64)
MODULE_PARM_DESC(ccn504_addr, "CCN-504 physical base address");
static u64 ccn504_addr = 0;
module_param(ccn504_addr, u64, 0444);
static void __iomem *gator_events_ccn504_base;
static bool gator_events_ccn504_global_enabled;
static unsigned long gator_events_ccn504_enabled[CNTMAX];
static unsigned long gator_events_ccn504_event[CNTMAX];
static unsigned long gator_events_ccn504_key[CNTMAX];
static int gator_events_ccn504_buffer[2*CNTMAX];
static int gator_events_ccn504_prev[CNTMAX];
static void gator_events_ccn504_create_shutdown(void)
{
if (gator_events_ccn504_base != NULL) {
iounmap(gator_events_ccn504_base);
}
}
static int gator_events_ccn504_create_files(struct super_block *sb, struct dentry *root)
{
struct dentry *dir;
int i;
char buf[32];
for (i = 0; i < CNTMAX; ++i) {
if (i == CCNT) {
snprintf(buf, sizeof(buf), "CCN-504_ccnt");
} else {
snprintf(buf, sizeof(buf), "CCN-504_cnt%i", i);
}
dir = gatorfs_mkdir(sb, root, buf);
if (!dir) {
return -1;
}
gatorfs_create_ulong(sb, dir, "enabled", &gator_events_ccn504_enabled[i]);
if (i != CCNT) {
gatorfs_create_ulong(sb, dir, "event", &gator_events_ccn504_event[i]);
}
gatorfs_create_ro_ulong(sb, dir, "key", &gator_events_ccn504_key[i]);
}
return 0;
}
static void gator_events_ccn504_set_dt_config(int xp_node_id, int event_num, int value)
{
u32 dt_config;
dt_config = readl(gator_events_ccn504_base + (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG);
dt_config |= (value + event_num) << (4*event_num);
writel(dt_config, gator_events_ccn504_base + (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG);
}
static int gator_events_ccn504_start(void)
{
int i;
gator_events_ccn504_global_enabled = 0;
for (i = 0; i < CNTMAX; ++i) {
if (gator_events_ccn504_enabled[i]) {
gator_events_ccn504_global_enabled = 1;
break;
}
}
if (!gator_events_ccn504_global_enabled) {
return 0;
}
memset(&gator_events_ccn504_prev, 0x80, sizeof(gator_events_ccn504_prev));
// Disable INTREQ on overflow
// [6] ovfl_intr_en = 0
// perhaps set to 1?
// [5] cntr_rst = 0
// No register paring
// [4:1] cntcfg = 0
// Enable PMU features
// [0] pmu_en = 1
writel(0x1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMCR);
// Configure the XPs
for (i = 0; i < NUM_XPS; ++i) {
int dt_control;
// Pass on all events
writel(0, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONFIG);
// Enable PMU capability
// [0] dt_enable = 1
dt_control = readl(gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONTROL);
dt_control |= 0x1;
writel(dt_control, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONTROL);
}
// Assume no other pmu_event_sel registers are set
// cycle counter does not need to be enabled
for (i = 0; i < CCNT; ++i) {
int pmu_event_id;
int node_type;
int region;
u32 pmu_event_sel;
u32 oly_id_whole;
u32 oly_id;
u32 node_id;
if (!gator_events_ccn504_enabled[i]) {
continue;
}
pmu_event_id = get_pmu_event_id(gator_events_ccn504_event[i]);
node_type = get_node_type(gator_events_ccn504_event[i]);
region = get_region(gator_events_ccn504_event[i]);
// Verify the node_type
oly_id_whole = readl(gator_events_ccn504_base + region*REGION_SIZE + OLY_ID);
oly_id = oly_id_whole & 0x1F;
node_id = (oly_id_whole >> 8) & 0x7F;
if ((oly_id != node_type) ||
((node_type == 0x16) && ((oly_id != 0x14) && (oly_id != 0x15) && (oly_id != 0x16) && (oly_id != 0x18) && (oly_id != 0x19) && (oly_id != 0x1A)))) {
printk(KERN_ERR "gator: oly_id is 0x%x expected 0x%x\n", oly_id, node_type);
return -1;
}
// Set the control register
pmu_event_sel = readl(gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL);
switch (node_type) {
case 0x08: // XP
pmu_event_sel |= pmu_event_id << (7*i);
gator_events_ccn504_set_dt_config(node_id, i, 0x4);
break;
case 0x04: // HN-F
case 0x16: // RN-I
case 0x10: // SBAS
pmu_event_sel |= pmu_event_id << (4*i);
gator_events_ccn504_set_dt_config(node_id/2, i, (node_id & 1) == 0 ? 0x8 : 0xC);
break;
}
writel(pmu_event_sel, gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL);
}
return 0;
}
static void gator_events_ccn504_stop(void)
{
int i;
if (!gator_events_ccn504_global_enabled) {
return;
}
// cycle counter does not need to be disabled
for (i = 0; i < CCNT; ++i) {
int region;
if (!gator_events_ccn504_enabled[i]) {
continue;
}
region = get_region(gator_events_ccn504_event[i]);
writel(0, gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL);
}
// Clear dt_config
for (i = 0; i < NUM_XPS; ++i) {
writel(0, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONFIG);
}
}
static int gator_events_ccn504_read(int **buffer)
{
int i;
int len = 0;
int value;
if (!on_primary_core() || !gator_events_ccn504_global_enabled) {
return 0;
}
// Verify the pmsr register is zero
while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) != 0);
// Request a PMU snapshot
writel(1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR_REQ);
// Wait for the snapshot
while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) == 0);
// Read the shadow registers
for (i = 0; i < CNTMAX; ++i) {
if (!gator_events_ccn504_enabled[i]) {
continue;
}
value = readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + (i == CCNT ? PMCCNTRSR : PMEVCNTSR0 + 8*i));
if (gator_events_ccn504_prev[i] != 0x80808080) {
gator_events_ccn504_buffer[len++] = gator_events_ccn504_key[i];
gator_events_ccn504_buffer[len++] = value - gator_events_ccn504_prev[i];
}
gator_events_ccn504_prev[i] = value;
// Are the counters registers cleared when read? Is that what the cntr_rst bit on the pmcr register does?
}
// Clear the PMU snapshot status
writel(1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR_CLR);
if (buffer)
*buffer = gator_events_ccn504_buffer;
return len;
}
static struct gator_interface gator_events_ccn504_interface = {
.shutdown = gator_events_ccn504_create_shutdown,
.create_files = gator_events_ccn504_create_files,
.start = gator_events_ccn504_start,
.stop = gator_events_ccn504_stop,
.read = gator_events_ccn504_read,
};
int gator_events_ccn504_init(void)
{
int i;
if (ccn504_addr == 0) {
return -1;
}
gator_events_ccn504_base = ioremap(ccn504_addr, NUM_REGIONS*REGION_SIZE);
if (gator_events_ccn504_base == NULL) {
printk(KERN_ERR "gator: ioremap returned NULL\n");
return -1;
}
for (i = 0; i < CNTMAX; ++i) {
gator_events_ccn504_enabled[i] = 0;
gator_events_ccn504_event[i] = 0;
gator_events_ccn504_key[i] = gator_events_get_key();
}
return gator_events_install(&gator_events_ccn504_interface);
}

View File

@@ -42,17 +42,15 @@ static int gator_events_irq_create_files(struct super_block *sb, struct dentry *
/* irq */
dir = gatorfs_mkdir(sb, root, "Linux_irq_irq");
if (!dir) {
if (!dir)
return -1;
}
gatorfs_create_ulong(sb, dir, "enabled", &hardirq_enabled);
gatorfs_create_ro_ulong(sb, dir, "key", &hardirq_key);
/* soft irq */
dir = gatorfs_mkdir(sb, root, "Linux_irq_softirq");
if (!dir) {
if (!dir)
return -1;
}
gatorfs_create_ulong(sb, dir, "enabled", &softirq_enabled);
gatorfs_create_ro_ulong(sb, dir, "key", &softirq_key);
@@ -63,7 +61,7 @@ static int gator_events_irq_online(int **buffer, bool migrate)
{
int len = 0, cpu = get_physical_cpu();
// synchronization with the irq_exit functions is not necessary as the values are being reset
/* synchronization with the irq_exit functions is not necessary as the values are being reset */
if (hardirq_enabled) {
atomic_set(&per_cpu(irqCnt, cpu)[HARDIRQ], 0);
per_cpu(irqGet, cpu)[len++] = hardirq_key;
@@ -84,7 +82,7 @@ static int gator_events_irq_online(int **buffer, bool migrate)
static int gator_events_irq_start(void)
{
// register tracepoints
/* register tracepoints */
if (hardirq_enabled)
if (GATOR_REGISTER_TRACE(irq_handler_exit))
goto fail_hardirq_exit;
@@ -95,7 +93,7 @@ static int gator_events_irq_start(void)
return 0;
// unregister tracepoints on error
/* unregister tracepoints on error */
fail_softirq_exit:
if (hardirq_enabled)
GATOR_UNREGISTER_TRACE(irq_handler_exit);
@@ -117,7 +115,7 @@ static void gator_events_irq_stop(void)
softirq_enabled = 0;
}
static int gator_events_irq_read(int **buffer)
static int gator_events_irq_read(int **buffer, bool sched_switch)
{
int len, value;
int cpu = get_physical_cpu();

View File

@@ -91,7 +91,7 @@ static void gator_events_l2c310_stop(void)
writel(0, l2c310_base + L2X0_EVENT_CNT_CTRL);
}
static int gator_events_l2c310_read(int **buffer)
static int gator_events_l2c310_read(int **buffer, bool sched_switch)
{
static const unsigned long l2x0_event_cntx_val[L2C310_COUNTERS_NUM] = {
L2X0_EVENT_CNT0_VAL,
@@ -149,8 +149,8 @@ static void __iomem *gator_events_l2c310_probe(void)
0xa0412000,
#endif
#if defined(CONFIG_ARCH_VEXPRESS)
0x1e00a000, // A9x4 core tile (HBI-0191)
0x2c0f0000, // New memory map tiles
0x1e00a000, /* A9x4 core tile (HBI-0191) */
0x2c0f0000, /* New memory map tiles */
#endif
};
int i;

View File

@@ -36,7 +36,7 @@
#elif GATOR_MALI_INTERFACE_STYLE == 2
#error GATOR_MALI_INTERFACE_STYLE 2 is obsolete
#elif GATOR_MALI_INTERFACE_STYLE >= 3
// Valid GATOR_MALI_INTERFACE_STYLE
/* Valid GATOR_MALI_INTERFACE_STYLE */
#else
#error Unknown GATOR_MALI_INTERFACE_STYLE option.
#endif
@@ -54,7 +54,7 @@
#error MALI_SUPPORT set to an invalid device code: expecting MALI_4xx
#endif
static const char mali_name[] = "Mali-4xx";
static const char mali_name[] = "4xx";
/* gatorfs variables for counter enable state,
* the event the counter should count and the
@@ -73,8 +73,8 @@ static u32 *counter_address[NUMBER_OF_EVENTS];
/* An array used to return the data we recorded
* as key,value pairs hence the *2
*/
static unsigned long counter_dump[NUMBER_OF_EVENTS * 2];
static unsigned long counter_prev[NUMBER_OF_EVENTS];
static int counter_dump[NUMBER_OF_EVENTS * 2];
static int counter_prev[NUMBER_OF_EVENTS];
static bool prev_set[NUMBER_OF_EVENTS];
/* Note whether tracepoints have been registered */
@@ -89,8 +89,8 @@ static unsigned int n_vp_cores = MAX_NUM_VP_CORES;
static unsigned int n_l2_cores = MAX_NUM_L2_CACHE_CORES;
static unsigned int n_fp_cores = MAX_NUM_FP_CORES;
extern mali_counter mali_activity[2];
static const char* const mali_activity_names[] = {
extern struct mali_counter mali_activity[2];
static const char *const mali_activity_names[] = {
"fragment",
"vertex",
};
@@ -112,36 +112,11 @@ static inline int is_hw_counter(unsigned int event_id)
return (event_id >= FIRST_HW_COUNTER && event_id <= LAST_HW_COUNTER);
}
/*
* These are provided for utgard compatibility.
*/
typedef void _mali_profiling_get_mali_version_type(struct _mali_profiling_mali_version *values);
typedef u32 _mali_profiling_get_l2_counters_type(_mali_profiling_l2_counter_values *values);
/* Probe for continuously sampled counter */
#if 0 //WE_DONT_CURRENTLY_USE_THIS_SO_SUPPRESS_WARNING
GATOR_DEFINE_PROBE(mali_sample_address, TP_PROTO(unsigned int event_id, u32 *addr))
{
/* Turning on too many pr_debug statements in frequently called functions
* can cause stability and/or performance problems
*/
//pr_debug("gator: mali_sample_address %d %d\n", event_id, addr);
if (event_id >= ACTIVITY_VP && event_id <= COUNTER_FP3_C1) {
counter_address[event_id] = addr;
}
}
#endif
/* Probe for hardware counter events */
GATOR_DEFINE_PROBE(mali_hw_counter, TP_PROTO(unsigned int event_id, unsigned int value))
{
/* Turning on too many pr_debug statements in frequently called functions
* can cause stability and/or performance problems
*/
//pr_debug("gator: mali_hw_counter %d %d\n", event_id, value);
if (is_hw_counter(event_id)) {
if (is_hw_counter(event_id))
counter_data[event_id] = value;
}
}
GATOR_DEFINE_PROBE(mali_sw_counters, TP_PROTO(pid_t pid, pid_t tid, void *surface_id, unsigned int *counters))
@@ -150,9 +125,8 @@ GATOR_DEFINE_PROBE(mali_sw_counters, TP_PROTO(pid_t pid, pid_t tid, void *surfac
/* Copy over the values for those counters which are enabled. */
for (i = FIRST_SW_COUNTER; i <= LAST_SW_COUNTER; i++) {
if (counter_enabled[i]) {
if (counter_enabled[i])
counter_data[i] = (u32)(counters[i - FIRST_SW_COUNTER]);
}
}
}
@@ -172,13 +146,11 @@ static int create_fs_entry(struct super_block *sb, struct dentry *root, const ch
dir = gatorfs_mkdir(sb, root, name);
if (!dir) {
if (!dir)
return -1;
}
if (create_event_item) {
if (create_event_item)
gatorfs_create_ulong(sb, dir, "event", &counter_event[event]);
}
gatorfs_create_ulong(sb, dir, "enabled", &counter_enabled[event]);
gatorfs_create_ro_ulong(sb, dir, "key", &counter_key[event]);
@@ -192,7 +164,7 @@ static int create_fs_entry(struct super_block *sb, struct dentry *root, const ch
*/
static void initialise_version_info(void)
{
_mali_profiling_get_mali_version_type *mali_profiling_get_mali_version_symbol;
void (*mali_profiling_get_mali_version_symbol)(struct _mali_profiling_mali_version *values);
mali_profiling_get_mali_version_symbol = symbol_get(_mali_profiling_get_mali_version);
@@ -214,8 +186,8 @@ static void initialise_version_info(void)
/* Release the function - we're done with it. */
symbol_put(_mali_profiling_get_mali_version);
} else {
printk("gator: mali online _mali_profiling_get_mali_version symbol not found\n");
printk("gator: check your Mali DDK version versus the GATOR_MALI_INTERFACE_STYLE setting\n");
pr_err("gator: mali online _mali_profiling_get_mali_version symbol not found\n");
pr_err("gator: check your Mali DDK version versus the GATOR_MALI_INTERFACE_STYLE setting\n");
}
}
#endif
@@ -242,26 +214,24 @@ static int create_files(struct super_block *sb, struct dentry *root)
mali_activity[0].cores = n_fp_cores;
mali_activity[1].cores = n_vp_cores;
for (event = 0; event < ARRAY_SIZE(mali_activity); event++) {
if (gator_mali_create_file_system(mali_name, mali_activity_names[event], sb, root, &mali_activity[event], NULL) != 0) {
if (gator_mali_create_file_system(mali_name, mali_activity_names[event], sb, root, &mali_activity[event], NULL) != 0)
return -1;
}
}
/* Vertex processor counters */
for (core_id = 0; core_id < n_vp_cores; core_id++) {
int activity_counter_id = ACTIVITY_VP_0;
snprintf(buf, sizeof buf, "ARM_%s_VP_%d_active", mali_name, core_id);
if (create_fs_entry(sb, root, buf, activity_counter_id, 0) != 0) {
snprintf(buf, sizeof(buf), "ARM_Mali-%s_VP_%d_active", mali_name, core_id);
if (create_fs_entry(sb, root, buf, activity_counter_id, 0) != 0)
return -1;
}
for (counter_number = 0; counter_number < 2; counter_number++) {
int counter_id = COUNTER_VP_0_C0 + (2 * core_id) + counter_number;
snprintf(buf, sizeof buf, "ARM_%s_VP_%d_cnt%d", mali_name, core_id, counter_number);
if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) {
snprintf(buf, sizeof(buf), "ARM_Mali-%s_VP_%d_cnt%d", mali_name, core_id, counter_number);
if (create_fs_entry(sb, root, buf, counter_id, 1) != 0)
return -1;
}
}
}
@@ -269,18 +239,16 @@ static int create_files(struct super_block *sb, struct dentry *root)
for (core_id = 0; core_id < n_fp_cores; core_id++) {
int activity_counter_id = ACTIVITY_FP_0 + core_id;
snprintf(buf, sizeof buf, "ARM_%s_FP_%d_active", mali_name, core_id);
if (create_fs_entry(sb, root, buf, activity_counter_id, 0) != 0) {
snprintf(buf, sizeof(buf), "ARM_Mali-%s_FP_%d_active", mali_name, core_id);
if (create_fs_entry(sb, root, buf, activity_counter_id, 0) != 0)
return -1;
}
for (counter_number = 0; counter_number < 2; counter_number++) {
int counter_id = COUNTER_FP_0_C0 + (2 * core_id) + counter_number;
snprintf(buf, sizeof buf, "ARM_%s_FP_%d_cnt%d", mali_name, core_id, counter_number);
if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) {
snprintf(buf, sizeof(buf), "ARM_Mali-%s_FP_%d_cnt%d", mali_name, core_id, counter_number);
if (create_fs_entry(sb, root, buf, counter_id, 1) != 0)
return -1;
}
}
}
@@ -289,38 +257,33 @@ static int create_files(struct super_block *sb, struct dentry *root)
for (counter_number = 0; counter_number < 2; counter_number++) {
int counter_id = COUNTER_L2_0_C0 + (2 * core_id) + counter_number;
snprintf(buf, sizeof buf, "ARM_%s_L2_%d_cnt%d", mali_name, core_id, counter_number);
if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) {
snprintf(buf, sizeof(buf), "ARM_Mali-%s_L2_%d_cnt%d", mali_name, core_id, counter_number);
if (create_fs_entry(sb, root, buf, counter_id, 1) != 0)
return -1;
}
}
}
/* Now set up the software counter entries */
for (event = FIRST_SW_COUNTER; event <= LAST_SW_COUNTER; event++) {
snprintf(buf, sizeof(buf), "ARM_%s_SW_%d", mali_name, event - FIRST_SW_COUNTER);
snprintf(buf, sizeof(buf), "ARM_Mali-%s_SW_%d", mali_name, event - FIRST_SW_COUNTER);
if (create_fs_entry(sb, root, buf, event, 0) != 0) {
if (create_fs_entry(sb, root, buf, event, 0) != 0)
return -1;
}
}
/* Now set up the special counter entries */
snprintf(buf, sizeof(buf), "ARM_%s_Filmstrip_cnt0", mali_name);
if (create_fs_entry(sb, root, buf, COUNTER_FILMSTRIP, 1) != 0) {
snprintf(buf, sizeof(buf), "ARM_Mali-%s_Filmstrip_cnt0", mali_name);
if (create_fs_entry(sb, root, buf, COUNTER_FILMSTRIP, 1) != 0)
return -1;
}
#ifdef DVFS_REPORTED_BY_DDK
snprintf(buf, sizeof(buf), "ARM_%s_Frequency", mali_name);
if (create_fs_entry(sb, root, buf, COUNTER_FREQUENCY, 1) != 0) {
snprintf(buf, sizeof(buf), "ARM_Mali-%s_Frequency", mali_name);
if (create_fs_entry(sb, root, buf, COUNTER_FREQUENCY, 1) != 0)
return -1;
}
snprintf(buf, sizeof(buf), "ARM_%s_Voltage", mali_name);
if (create_fs_entry(sb, root, buf, COUNTER_VOLTAGE, 1) != 0) {
snprintf(buf, sizeof(buf), "ARM_Mali-%s_Voltage", mali_name);
if (create_fs_entry(sb, root, buf, COUNTER_VOLTAGE, 1) != 0)
return -1;
}
#endif
return 0;
@@ -330,8 +293,8 @@ static int create_files(struct super_block *sb, struct dentry *root)
* Local store for the get_counters entry point into the DDK.
* This is stored here since it is used very regularly.
*/
static mali_profiling_get_counters_type *mali_get_counters = NULL;
static _mali_profiling_get_l2_counters_type *mali_get_l2_counters = NULL;
static void (*mali_get_counters)(unsigned int *, unsigned int *, unsigned int *, unsigned int *);
static u32 (*mali_get_l2_counters)(struct _mali_profiling_l2_counter_values *values);
/*
* Examine list of counters between two index limits and determine if any one is enabled.
@@ -342,9 +305,8 @@ static int is_any_counter_enabled(unsigned int first_counter, unsigned int last_
unsigned int i;
for (i = first_counter; i <= last_counter; i++) {
if (counter_enabled[i]) {
if (counter_enabled[i])
return 1; /* At least one counter is enabled */
}
}
return 0; /* No s/w counters enabled */
@@ -366,16 +328,15 @@ static void init_counters(unsigned int from_counter, unsigned int to_counter)
pr_debug("gator: mali online _mali_profiling_set_event symbol @ %p\n", mali_set_hw_event);
for (counter_id = from_counter; counter_id <= to_counter; counter_id++) {
if (counter_enabled[counter_id]) {
if (counter_enabled[counter_id])
mali_set_hw_event(counter_id, counter_event[counter_id]);
} else {
else
mali_set_hw_event(counter_id, 0xFFFFFFFF);
}
}
symbol_put(_mali_profiling_set_event);
} else {
printk("gator: mali online _mali_profiling_set_event symbol not found\n");
pr_err("gator: mali online _mali_profiling_set_event symbol not found\n");
}
}
@@ -407,27 +368,23 @@ static void mali_counter_initialize(void)
symbol_put(_mali_profiling_control);
} else {
printk("gator: mali online _mali_profiling_control symbol not found\n");
pr_err("gator: mali online _mali_profiling_control symbol not found\n");
}
mali_get_counters = symbol_get(_mali_profiling_get_counters);
if (mali_get_counters) {
if (mali_get_counters)
pr_debug("gator: mali online _mali_profiling_get_counters symbol @ %p\n", mali_get_counters);
} else {
pr_debug("gator WARNING: mali _mali_profiling_get_counters symbol not defined");
}
else
pr_debug("gator WARNING: mali _mali_profiling_get_counters symbol not defined\n");
mali_get_l2_counters = symbol_get(_mali_profiling_get_l2_counters);
if (mali_get_l2_counters) {
if (mali_get_l2_counters)
pr_debug("gator: mali online _mali_profiling_get_l2_counters symbol @ %p\n", mali_get_l2_counters);
} else {
pr_debug("gator WARNING: mali _mali_profiling_get_l2_counters symbol not defined");
}
else
pr_debug("gator WARNING: mali _mali_profiling_get_l2_counters symbol not defined\n");
if (!mali_get_counters && !mali_get_l2_counters) {
pr_debug("gator: WARNING: no L2 counters available");
pr_debug("gator: WARNING: no L2 counters available\n");
n_l2_cores = 0;
}
@@ -449,13 +406,12 @@ static void mali_counter_deinitialize(void)
int i;
pr_debug("gator: mali offline _mali_profiling_set_event symbol @ %p\n", mali_set_hw_event);
for (i = FIRST_HW_COUNTER; i <= LAST_HW_COUNTER; i++) {
for (i = FIRST_HW_COUNTER; i <= LAST_HW_COUNTER; i++)
mali_set_hw_event(i, 0xFFFFFFFF);
}
symbol_put(_mali_profiling_set_event);
} else {
printk("gator: mali offline _mali_profiling_set_event symbol not found\n");
pr_err("gator: mali offline _mali_profiling_set_event symbol not found\n");
}
/* Generic control interface for Mali DDK. */
@@ -471,29 +427,27 @@ static void mali_counter_deinitialize(void)
symbol_put(_mali_profiling_control);
} else {
printk("gator: mali offline _mali_profiling_control symbol not found\n");
pr_err("gator: mali offline _mali_profiling_control symbol not found\n");
}
if (mali_get_counters) {
if (mali_get_counters)
symbol_put(_mali_profiling_get_counters);
}
if (mali_get_l2_counters) {
if (mali_get_l2_counters)
symbol_put(_mali_profiling_get_l2_counters);
}
}
static int start(void)
{
// register tracepoints
/* register tracepoints */
if (GATOR_REGISTER_TRACE(mali_hw_counter)) {
printk("gator: mali_hw_counter tracepoint failed to activate\n");
pr_err("gator: mali_hw_counter tracepoint failed to activate\n");
return -1;
}
/* For Mali drivers with built-in support. */
if (GATOR_REGISTER_TRACE(mali_sw_counters)) {
printk("gator: mali_sw_counters tracepoint failed to activate\n");
pr_err("gator: mali_sw_counters tracepoint failed to activate\n");
return -1;
}
@@ -543,17 +497,17 @@ static void dump_counters(unsigned int from_counter, unsigned int to_counter, un
}
}
static int read(int **buffer)
static int read(int **buffer, bool sched_switch)
{
int len = 0;
if (!on_primary_core())
return 0;
// Read the L2 C0 and C1 here.
/* Read the L2 C0 and C1 here. */
if (n_l2_cores > 0 && is_any_counter_enabled(COUNTER_L2_0_C0, COUNTER_L2_0_C0 + (2 * n_l2_cores))) {
unsigned int unavailable_l2_caches = 0;
_mali_profiling_l2_counter_values cache_values;
struct _mali_profiling_l2_counter_values cache_values;
unsigned int cache_id;
struct _mali_profiling_core_counters *per_core;
@@ -572,25 +526,24 @@ static int read(int **buffer)
unsigned int counter_id_0 = COUNTER_L2_0_C0 + (2 * cache_id);
unsigned int counter_id_1 = counter_id_0 + 1;
if ((1 << cache_id) & unavailable_l2_caches) {
if ((1 << cache_id) & unavailable_l2_caches)
continue; /* This cache is unavailable (powered-off, possibly). */
}
per_core = &cache_values.cores[cache_id];
if (counter_enabled[counter_id_0] && prev_set[counter_id_0]) {
// Calculate and save src0's counter val0
/* Calculate and save src0's counter val0 */
counter_dump[len++] = counter_key[counter_id_0];
counter_dump[len++] = per_core->value0 - counter_prev[counter_id_0];
}
if (counter_enabled[counter_id_1] && prev_set[counter_id_1]) {
// Calculate and save src1's counter val1
/* Calculate and save src1's counter val1 */
counter_dump[len++] = counter_key[counter_id_1];
counter_dump[len++] = per_core->value1 - counter_prev[counter_id_1];
}
// Save the previous values for the counters.
/* Save the previous values for the counters. */
counter_prev[counter_id_0] = per_core->value0;
prev_set[counter_id_0] = true;
counter_prev[counter_id_1] = per_core->value1;
@@ -608,8 +561,9 @@ static int read(int **buffer)
{
int cnt;
/*
* Add in the voltage and frequency counters if enabled. Note that, since these are
* actually passed as events, the counter value should not be cleared.
* Add in the voltage and frequency counters if enabled. Note
* that, since these are actually passed as events, the counter
* value should not be cleared.
*/
cnt = COUNTER_FREQUENCY;
if (counter_enabled[cnt]) {
@@ -625,9 +579,8 @@ static int read(int **buffer)
}
#endif
if (buffer) {
*buffer = (int *)counter_dump;
}
if (buffer)
*buffer = counter_dump;
return len;
}

View File

@@ -8,7 +8,7 @@
*/
#include "gator_events_mali_common.h"
extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, mali_counter *counter, unsigned long *event)
extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, struct mali_counter *counter, unsigned long *event)
{
int err;
char buf[255];
@@ -17,36 +17,39 @@ extern int gator_mali_create_file_system(const char *mali_name, const char *even
/* If the counter name is empty ignore it */
if (strlen(event_name) != 0) {
/* Set up the filesystem entry for this event. */
snprintf(buf, sizeof(buf), "ARM_%s_%s", mali_name, event_name);
if (mali_name == NULL)
snprintf(buf, sizeof(buf), "ARM_Mali-%s", event_name);
else
snprintf(buf, sizeof(buf), "ARM_Mali-%s_%s", mali_name, event_name);
dir = gatorfs_mkdir(sb, root, buf);
if (dir == NULL) {
pr_debug("gator: %s: error creating file system for: %s (%s)", mali_name, event_name, buf);
pr_debug("gator: %s: error creating file system for: %s (%s)\n", mali_name, event_name, buf);
return -1;
}
err = gatorfs_create_ulong(sb, dir, "enabled", &counter->enabled);
if (err != 0) {
pr_debug("gator: %s: error calling gatorfs_create_ulong for: %s (%s)", mali_name, event_name, buf);
pr_debug("gator: %s: error calling gatorfs_create_ulong for: %s (%s)\n", mali_name, event_name, buf);
return -1;
}
err = gatorfs_create_ro_ulong(sb, dir, "key", &counter->key);
if (err != 0) {
pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)", mali_name, event_name, buf);
pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf);
return -1;
}
if (counter->cores != -1) {
err = gatorfs_create_ro_ulong(sb, dir, "cores", &counter->cores);
if (err != 0) {
pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)", mali_name, event_name, buf);
pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf);
return -1;
}
}
if (event != NULL) {
err = gatorfs_create_ulong(sb, dir, "event", event);
if (err != 0) {
pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)", mali_name, event_name, buf);
pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf);
return -1;
}
}
@@ -55,12 +58,12 @@ extern int gator_mali_create_file_system(const char *mali_name, const char *even
return 0;
}
extern void gator_mali_initialise_counters(mali_counter counters[], unsigned int n_counters)
extern void gator_mali_initialise_counters(struct mali_counter counters[], unsigned int n_counters)
{
unsigned int cnt;
for (cnt = 0; cnt < n_counters; cnt++) {
mali_counter *counter = &counters[cnt];
struct mali_counter *counter = &counters[cnt];
counter->key = gator_events_get_key();
counter->enabled = 0;

View File

@@ -16,7 +16,7 @@
#include <linux/time.h>
#include <linux/math64.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <linux/io.h>
/* Ensure that MALI_SUPPORT has been defined to something. */
#ifndef MALI_SUPPORT
@@ -30,21 +30,20 @@
/*
* Runtime state information for a counter.
*/
typedef struct {
// 'key' (a unique id set by gatord and returned by gator.ko)
struct mali_counter {
/* 'key' (a unique id set by gatord and returned by gator.ko) */
unsigned long key;
// counter enable state
/* counter enable state */
unsigned long enabled;
// for activity counters, the number of cores, otherwise -1
/* for activity counters, the number of cores, otherwise -1 */
unsigned long cores;
} mali_counter;
};
/*
* Mali-4xx
*/
typedef int mali_profiling_set_event_type(unsigned int, int);
typedef void mali_profiling_control_type(unsigned int, unsigned int);
typedef void mali_profiling_get_counters_type(unsigned int *, unsigned int *, unsigned int *, unsigned int *);
/*
* Driver entry points for functions called directly by gator.
@@ -65,7 +64,7 @@ extern void _mali_profiling_get_counters(unsigned int *, unsigned int *, unsigne
*
* @return 0 if entry point was created, non-zero if not.
*/
extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, mali_counter *counter, unsigned long *event);
extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, struct mali_counter *counter, unsigned long *event);
/**
* Initializes the counter array.
@@ -73,6 +72,6 @@ extern int gator_mali_create_file_system(const char *mali_name, const char *even
* @param keys The array of counters
* @param n_counters The number of entries in each of the arrays.
*/
extern void gator_mali_initialise_counters(mali_counter counters[], unsigned int n_counters);
extern void gator_mali_initialise_counters(struct mali_counter counters[], unsigned int n_counters);
#endif /* GATOR_EVENTS_MALI_COMMON_H */

View File

@@ -13,7 +13,7 @@
#include <linux/time.h>
#include <linux/math64.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <linux/io.h>
#ifdef MALI_DIR_MIDGARD
/* New DDK Directory structure with kernel/drivers/gpu/arm/midgard*/
@@ -28,13 +28,13 @@
/*
* Check that the MALI_SUPPORT define is set to one of the allowable device codes.
*/
#if (MALI_SUPPORT != MALI_T6xx)
#error MALI_SUPPORT set to an invalid device code: expecting MALI_T6xx
#if (MALI_SUPPORT != MALI_MIDGARD)
#error MALI_SUPPORT set to an invalid device code: expecting MALI_MIDGARD
#endif
static const char mali_name[] = "Mali-T6xx";
static const char mali_name[] = "Midgard";
/* Counters for Mali-T6xx:
/* Counters for Mali-Midgard:
*
* - Timeline events
* They are tracepoints, but instead of reporting a number they report a START/STOP event.
@@ -49,7 +49,7 @@ static const char mali_name[] = "Mali-T6xx";
*/
/* Timeline (start/stop) activity */
static const char *timeline_event_names[] = {
static const char *const timeline_event_names[] = {
"PM_SHADER_0",
"PM_SHADER_1",
"PM_SHADER_2",
@@ -88,7 +88,7 @@ enum {
#define NUM_PM_SHADER (8)
/* Software Counters */
static const char *software_counter_names[] = {
static const char *const software_counter_names[] = {
"MMU_PAGE_FAULT_0",
"MMU_PAGE_FAULT_1",
"MMU_PAGE_FAULT_2",
@@ -103,7 +103,7 @@ enum {
};
/* Software Counters */
static const char *accumulators_names[] = {
static const char *const accumulators_names[] = {
"TOTAL_ALLOC_PAGES"
};
@@ -123,17 +123,18 @@ enum {
/*
* gatorfs variables for counter enable state
*/
static mali_counter counters[NUMBER_OF_EVENTS];
static struct mali_counter counters[NUMBER_OF_EVENTS];
static unsigned long filmstrip_event;
/* An array used to return the data we recorded
* as key,value pairs hence the *2
*/
static unsigned long counter_dump[NUMBER_OF_EVENTS * 2];
static int counter_dump[NUMBER_OF_EVENTS * 2];
/*
* Array holding counter start times (in ns) for each counter. A zero here
* indicates that the activity monitored by this counter is not running.
* Array holding counter start times (in ns) for each counter. A zero
* here indicates that the activity monitored by this counter is not
* running.
*/
static struct timespec timeline_event_starttime[NUMBER_OF_TIMELINE_EVENTS];
@@ -156,6 +157,7 @@ static struct timespec prev_timestamp;
static inline long get_duration_us(const struct timespec *start, const struct timespec *end)
{
long event_duration_us = (end->tv_nsec - start->tv_nsec) / 1000;
event_duration_us += (end->tv_sec - start->tv_sec) * 1000000;
return event_duration_us;
@@ -172,9 +174,8 @@ static void record_timeline_event(unsigned int timeline_index, unsigned int type
getnstimeofday(&event_timestamp);
/* Remember the start time if the activity is not already started */
if (event_start->tv_sec == 0) {
if (event_start->tv_sec == 0)
*event_start = event_timestamp; /* Structure copy */
}
break;
case ACTIVITY_STOP:
@@ -208,9 +209,9 @@ GATOR_DEFINE_PROBE(mali_pm_status, TP_PROTO(unsigned int event_id, unsigned long
#define L2_PRESENT_LO 0x120 /* (RO) Level 2 cache present bitmap, low word */
#define BIT_AT(value, pos) ((value >> pos) & 1)
static unsigned long long previous_shader_bitmask = 0;
static unsigned long long previous_tiler_bitmask = 0;
static unsigned long long previous_l2_bitmask = 0;
static unsigned long long previous_shader_bitmask;
static unsigned long long previous_tiler_bitmask;
static unsigned long long previous_l2_bitmask;
switch (event_id) {
case SHADER_PRESENT_LO:
@@ -219,9 +220,8 @@ GATOR_DEFINE_PROBE(mali_pm_status, TP_PROTO(unsigned int event_id, unsigned long
int pos;
for (pos = 0; pos < NUM_PM_SHADER; ++pos) {
if (BIT_AT(changed_bitmask, pos)) {
if (BIT_AT(changed_bitmask, pos))
record_timeline_event(PM_SHADER_0 + pos, BIT_AT(value, pos) ? ACTIVITY_START : ACTIVITY_STOP);
}
}
previous_shader_bitmask = value;
@@ -232,9 +232,8 @@ GATOR_DEFINE_PROBE(mali_pm_status, TP_PROTO(unsigned int event_id, unsigned long
{
unsigned long long changed = previous_tiler_bitmask ^ value;
if (BIT_AT(changed, 0)) {
if (BIT_AT(changed, 0))
record_timeline_event(PM_TILER_0, BIT_AT(value, 0) ? ACTIVITY_START : ACTIVITY_STOP);
}
previous_tiler_bitmask = value;
break;
@@ -244,12 +243,10 @@ GATOR_DEFINE_PROBE(mali_pm_status, TP_PROTO(unsigned int event_id, unsigned long
{
unsigned long long changed = previous_l2_bitmask ^ value;
if (BIT_AT(changed, 0)) {
if (BIT_AT(changed, 0))
record_timeline_event(PM_L2_0, BIT_AT(value, 0) ? ACTIVITY_START : ACTIVITY_STOP);
}
if (BIT_AT(changed, 4)) {
if (BIT_AT(changed, 4))
record_timeline_event(PM_L2_1, BIT_AT(value, 4) ? ACTIVITY_START : ACTIVITY_STOP);
}
previous_l2_bitmask = value;
break;
@@ -297,31 +294,27 @@ static int create_files(struct super_block *sb, struct dentry *root)
mali_profiling_control_type *mali_control;
for (event = FIRST_TIMELINE_EVENT; event < FIRST_TIMELINE_EVENT + NUMBER_OF_TIMELINE_EVENTS; event++) {
if (gator_mali_create_file_system(mali_name, timeline_event_names[counter_index], sb, root, &counters[event], NULL) != 0) {
if (gator_mali_create_file_system(mali_name, timeline_event_names[counter_index], sb, root, &counters[event], NULL) != 0)
return -1;
}
counter_index++;
}
counter_index = 0;
for (event = FIRST_SOFTWARE_COUNTER; event < FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS; event++) {
if (gator_mali_create_file_system(mali_name, software_counter_names[counter_index], sb, root, &counters[event], NULL) != 0) {
if (gator_mali_create_file_system(mali_name, software_counter_names[counter_index], sb, root, &counters[event], NULL) != 0)
return -1;
}
counter_index++;
}
counter_index = 0;
for (event = FIRST_ACCUMULATOR; event < FIRST_ACCUMULATOR + NUMBER_OF_ACCUMULATORS; event++) {
if (gator_mali_create_file_system(mali_name, accumulators_names[counter_index], sb, root, &counters[event], NULL) != 0) {
if (gator_mali_create_file_system(mali_name, accumulators_names[counter_index], sb, root, &counters[event], NULL) != 0)
return -1;
}
counter_index++;
}
mali_control = symbol_get(_mali_profiling_control);
if (mali_control) {
if (gator_mali_create_file_system(mali_name, "Filmstrip_cnt0", sb, root, &counters[FILMSTRIP], &filmstrip_event) != 0) {
if (gator_mali_create_file_system(mali_name, "Filmstrip_cnt0", sb, root, &counters[FILMSTRIP], &filmstrip_event) != 0)
return -1;
}
symbol_put(_mali_profiling_control);
}
@@ -331,36 +324,36 @@ static int create_files(struct super_block *sb, struct dentry *root)
static int register_tracepoints(void)
{
if (GATOR_REGISTER_TRACE(mali_pm_status)) {
pr_debug("gator: Mali-T6xx: mali_pm_status tracepoint failed to activate\n");
pr_debug("gator: Mali-Midgard: mali_pm_status tracepoint failed to activate\n");
return 0;
}
if (GATOR_REGISTER_TRACE(mali_page_fault_insert_pages)) {
pr_debug("gator: Mali-T6xx: mali_page_fault_insert_pages tracepoint failed to activate\n");
pr_debug("gator: Mali-Midgard: mali_page_fault_insert_pages tracepoint failed to activate\n");
return 0;
}
if (GATOR_REGISTER_TRACE(mali_mmu_as_in_use)) {
pr_debug("gator: Mali-T6xx: mali_mmu_as_in_use tracepoint failed to activate\n");
pr_debug("gator: Mali-Midgard: mali_mmu_as_in_use tracepoint failed to activate\n");
return 0;
}
if (GATOR_REGISTER_TRACE(mali_mmu_as_released)) {
pr_debug("gator: Mali-T6xx: mali_mmu_as_released tracepoint failed to activate\n");
pr_debug("gator: Mali-Midgard: mali_mmu_as_released tracepoint failed to activate\n");
return 0;
}
if (GATOR_REGISTER_TRACE(mali_total_alloc_pages_change)) {
pr_debug("gator: Mali-T6xx: mali_total_alloc_pages_change tracepoint failed to activate\n");
pr_debug("gator: Mali-Midgard: mali_total_alloc_pages_change tracepoint failed to activate\n");
return 0;
}
pr_debug("gator: Mali-T6xx: start\n");
pr_debug("gator: Mali-T6xx: mali_pm_status probe is at %p\n", &probe_mali_pm_status);
pr_debug("gator: Mali-T6xx: mali_page_fault_insert_pages probe is at %p\n", &probe_mali_page_fault_insert_pages);
pr_debug("gator: Mali-T6xx: mali_mmu_as_in_use probe is at %p\n", &probe_mali_mmu_as_in_use);
pr_debug("gator: Mali-T6xx: mali_mmu_as_released probe is at %p\n", &probe_mali_mmu_as_released);
pr_debug("gator: Mali-T6xx: mali_total_alloc_pages_change probe is at %p\n", &probe_mali_total_alloc_pages_change);
pr_debug("gator: Mali-Midgard: start\n");
pr_debug("gator: Mali-Midgard: mali_pm_status probe is at %p\n", &probe_mali_pm_status);
pr_debug("gator: Mali-Midgard: mali_page_fault_insert_pages probe is at %p\n", &probe_mali_page_fault_insert_pages);
pr_debug("gator: Mali-Midgard: mali_mmu_as_in_use probe is at %p\n", &probe_mali_mmu_as_in_use);
pr_debug("gator: Mali-Midgard: mali_mmu_as_released probe is at %p\n", &probe_mali_mmu_as_released);
pr_debug("gator: Mali-Midgard: mali_total_alloc_pages_change probe is at %p\n", &probe_mali_total_alloc_pages_change);
return 1;
}
@@ -376,18 +369,15 @@ static int start(void)
timeline_data[cnt] = 0;
}
for (cnt = 0; cnt < NUMBER_OF_SOFTWARE_COUNTERS; cnt++) {
for (cnt = 0; cnt < NUMBER_OF_SOFTWARE_COUNTERS; cnt++)
sw_counter_data[cnt] = 0;
}
for (cnt = 0; cnt < NUMBER_OF_ACCUMULATORS; cnt++) {
for (cnt = 0; cnt < NUMBER_OF_ACCUMULATORS; cnt++)
accumulators_data[cnt] = 0;
}
/* Register tracepoints */
if (register_tracepoints() == 0) {
if (register_tracepoints() == 0)
return -1;
}
/* Generic control interface for Mali DDK. */
mali_control = symbol_get(_mali_profiling_control);
@@ -410,7 +400,7 @@ static int start(void)
symbol_put(_mali_profiling_control);
} else {
printk("gator: mali online _mali_profiling_control symbol not found\n");
pr_err("gator: mali online _mali_profiling_control symbol not found\n");
}
/*
@@ -427,26 +417,26 @@ static void stop(void)
{
mali_profiling_control_type *mali_control;
pr_debug("gator: Mali-T6xx: stop\n");
pr_debug("gator: Mali-Midgard: stop\n");
/*
* It is safe to unregister traces even if they were not successfully
* registered, so no need to check.
*/
GATOR_UNREGISTER_TRACE(mali_pm_status);
pr_debug("gator: Mali-T6xx: mali_pm_status tracepoint deactivated\n");
pr_debug("gator: Mali-Midgard: mali_pm_status tracepoint deactivated\n");
GATOR_UNREGISTER_TRACE(mali_page_fault_insert_pages);
pr_debug("gator: Mali-T6xx: mali_page_fault_insert_pages tracepoint deactivated\n");
pr_debug("gator: Mali-Midgard: mali_page_fault_insert_pages tracepoint deactivated\n");
GATOR_UNREGISTER_TRACE(mali_mmu_as_in_use);
pr_debug("gator: Mali-T6xx: mali_mmu_as_in_use tracepoint deactivated\n");
pr_debug("gator: Mali-Midgard: mali_mmu_as_in_use tracepoint deactivated\n");
GATOR_UNREGISTER_TRACE(mali_mmu_as_released);
pr_debug("gator: Mali-T6xx: mali_mmu_as_released tracepoint deactivated\n");
pr_debug("gator: Mali-Midgard: mali_mmu_as_released tracepoint deactivated\n");
GATOR_UNREGISTER_TRACE(mali_total_alloc_pages_change);
pr_debug("gator: Mali-T6xx: mali_total_alloc_pages_change tracepoint deactivated\n");
pr_debug("gator: Mali-Midgard: mali_total_alloc_pages_change tracepoint deactivated\n");
/* Generic control interface for Mali DDK. */
mali_control = symbol_get(_mali_profiling_control);
@@ -457,20 +447,19 @@ static void stop(void)
symbol_put(_mali_profiling_control);
} else {
printk("gator: mali offline _mali_profiling_control symbol not found\n");
pr_err("gator: mali offline _mali_profiling_control symbol not found\n");
}
}
static int read(int **buffer)
static int read(int **buffer, bool sched_switch)
{
int cnt;
int len = 0;
long sample_interval_us = 0;
struct timespec read_timestamp;
if (!on_primary_core()) {
if (!on_primary_core())
return 0;
}
/* Get the start of this sample period. */
getnstimeofday(&read_timestamp);
@@ -479,9 +468,8 @@ static int read(int **buffer)
* Calculate the sample interval if the previous sample time is valid.
* We use tv_sec since it will not be 0.
*/
if (prev_timestamp.tv_sec != 0) {
if (prev_timestamp.tv_sec != 0)
sample_interval_us = get_duration_us(&prev_timestamp, &read_timestamp);
}
/* Structure copy. Update the previous timestamp. */
prev_timestamp = read_timestamp;
@@ -490,15 +478,19 @@ static int read(int **buffer)
* Report the timeline counters (ACTIVITY_START/STOP)
*/
for (cnt = FIRST_TIMELINE_EVENT; cnt < (FIRST_TIMELINE_EVENT + NUMBER_OF_TIMELINE_EVENTS); cnt++) {
mali_counter *counter = &counters[cnt];
struct mali_counter *counter = &counters[cnt];
if (counter->enabled) {
const int index = cnt - FIRST_TIMELINE_EVENT;
unsigned int value;
/* If the activity is still running, reset its start time to the start of this sample period
* to correct the count. Add the time up to the end of the sample onto the count. */
/* If the activity is still running, reset its start time to the
* start of this sample period to correct the count. Add the
* time up to the end of the sample onto the count.
*/
if (timeline_event_starttime[index].tv_sec != 0) {
const long event_duration = get_duration_us(&timeline_event_starttime[index], &read_timestamp);
timeline_data[index] += event_duration;
timeline_event_starttime[index] = read_timestamp; /* Activity is still running. */
}
@@ -507,7 +499,7 @@ static int read(int **buffer)
/* Convert the counter to a percent-of-sample value */
value = (timeline_data[index] * 100) / sample_interval_us;
} else {
pr_debug("gator: Mali-T6xx: setting value to zero\n");
pr_debug("gator: Mali-Midgard: setting value to zero\n");
value = 0;
}
@@ -521,9 +513,11 @@ static int read(int **buffer)
/* Report the software counters */
for (cnt = FIRST_SOFTWARE_COUNTER; cnt < (FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS); cnt++) {
const mali_counter *counter = &counters[cnt];
const struct mali_counter *counter = &counters[cnt];
if (counter->enabled) {
const int index = cnt - FIRST_SOFTWARE_COUNTER;
counter_dump[len++] = counter->key;
counter_dump[len++] = sw_counter_data[index];
/* Set the value to zero for the next time */
@@ -533,9 +527,11 @@ static int read(int **buffer)
/* Report the accumulators */
for (cnt = FIRST_ACCUMULATOR; cnt < (FIRST_ACCUMULATOR + NUMBER_OF_ACCUMULATORS); cnt++) {
const mali_counter *counter = &counters[cnt];
const struct mali_counter *counter = &counters[cnt];
if (counter->enabled) {
const int index = cnt - FIRST_ACCUMULATOR;
counter_dump[len++] = counter->key;
counter_dump[len++] = accumulators_data[index];
/* Do not zero the accumulator */
@@ -543,25 +539,24 @@ static int read(int **buffer)
}
/* Update the buffer */
if (buffer) {
*buffer = (int *)counter_dump;
}
if (buffer)
*buffer = counter_dump;
return len;
}
static struct gator_interface gator_events_mali_t6xx_interface = {
static struct gator_interface gator_events_mali_midgard_interface = {
.create_files = create_files,
.start = start,
.stop = stop,
.read = read
};
extern int gator_events_mali_t6xx_init(void)
extern int gator_events_mali_midgard_init(void)
{
pr_debug("gator: Mali-T6xx: sw_counters init\n");
pr_debug("gator: Mali-Midgard: sw_counters init\n");
gator_mali_initialise_counters(counters, NUMBER_OF_EVENTS);
return gator_events_install(&gator_events_mali_t6xx_interface);
return gator_events_install(&gator_events_mali_midgard_interface);
}

Some files were not shown because too many files have changed in this diff Show More