mirror of
https://github.com/armbian/linux.git
synced 2026-01-06 10:13:00 -08:00
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user