aboutsummaryrefslogtreecommitdiff
path: root/driver
diff options
context:
space:
mode:
Diffstat (limited to 'driver')
-rw-r--r--driver/Makefile7
-rw-r--r--driver/gator_annotate.c9
-rw-r--r--driver/gator_cookies.c14
-rw-r--r--driver/gator_ebs.c18
-rw-r--r--driver/gator_events_mali_400.c (renamed from driver/gator_events_mali.c)335
-rw-r--r--driver/gator_events_mali_400.h19
-rw-r--r--driver/gator_events_mali_common.c79
-rw-r--r--driver/gator_events_mali_common.h85
-rw-r--r--driver/gator_events_mali_t6xx.c553
-rw-r--r--driver/gator_events_mali_t6xx_hw.c571
-rw-r--r--driver/gator_events_meminfo.c20
-rw-r--r--driver/gator_events_net.c19
-rw-r--r--driver/gator_events_perf_pmu.c20
-rw-r--r--driver/gator_fs.c1
-rw-r--r--driver/gator_main.c28
-rw-r--r--driver/gator_trace_gpu.c152
-rw-r--r--driver/mali_t6xx.mk24
17 files changed, 1720 insertions, 234 deletions
diff --git a/driver/Makefile b/driver/Makefile
index 667637e..025dd9e 100644
--- a/driver/Makefile
+++ b/driver/Makefile
@@ -17,10 +17,13 @@ gator-y += gator_events_mmaped.o
ifneq ($(GATOR_WITH_MALI_SUPPORT),)
ifeq ($(GATOR_WITH_MALI_SUPPORT),MALI_T6xx)
-gator-y += gator_events_mali_t6xx.o
+gator-y += gator_events_mali_t6xx.o \
+ gator_events_mali_t6xx_hw.o
+include $(M)/mali_t6xx.mk
else
-gator-y += gator_events_mali.o
+gator-y += gator_events_mali_400.o
endif
+gator-y += gator_events_mali_common.o
EXTRA_CFLAGS += -DMALI_SUPPORT=$(GATOR_WITH_MALI_SUPPORT)
endif
diff --git a/driver/gator_annotate.c b/driver/gator_annotate.c
index b2288b3..b444789 100644
--- a/driver/gator_annotate.c
+++ b/driver/gator_annotate.c
@@ -43,9 +43,9 @@ static ssize_t annotate_write(struct file *file, char const __user *buf, size_t
if (*offset)
return -EINVAL;
- if (!collect_annotations) {
+ if (!collect_annotations)
+ // Not collecting annotations, tell the caller everything was written
return count_orig;
- }
cpu = 0; // Annotation only uses a single per-cpu buffer as the data must be in order to the engine
@@ -64,6 +64,8 @@ static ssize_t annotate_write(struct file *file, char const __user *buf, size_t
size = count < available ? count : available;
if (size <= 0) {
+ // Buffer is full but don't return an error. Instead return 0 so the
+ // caller knows nothing was written and they can try again.
size = 0;
goto annotate_write_out;
}
@@ -115,8 +117,9 @@ static int annotate_release(struct inode *inode, struct file *file)
// synchronize between cores
spin_lock(&annotate_lock);
- if (per_cpu(gator_buffer, cpu)[ANNOTATE_BUF] && buffer_check_space(cpu, ANNOTATE_BUF, MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) {
+ if (per_cpu(gator_buffer, cpu)[ANNOTATE_BUF] && buffer_check_space(cpu, ANNOTATE_BUF, MAXSIZE_PACK64 + 3 * MAXSIZE_PACK32)) {
uint32_t tid = current->pid;
+ gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, smp_processor_id());
gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, tid);
gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, 0); // time
gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, 0); // size
diff --git a/driver/gator_cookies.c b/driver/gator_cookies.c
index 7b50916..d7d8e84 100644
--- a/driver/gator_cookies.c
+++ b/driver/gator_cookies.c
@@ -25,6 +25,8 @@ static DEFINE_PER_CPU(unsigned int *, translate_buffer);
static inline uint32_t get_cookie(int cpu, int buftype, struct task_struct *task, struct vm_area_struct *vma, struct module *mod, bool in_interrupt);
static void wq_cookie_handler(struct work_struct *unused);
DECLARE_WORK(cookie_work, wq_cookie_handler);
+static struct timer_list app_process_wake_up_timer;
+static void app_process_wake_up_handler(unsigned long unused_data);
static uint32_t cookiemap_code(uint64_t value64) {
uint32_t value = (uint32_t)((value64 >> 32) + value64);
@@ -136,6 +138,12 @@ static void wq_cookie_handler(struct work_struct *unused)
mutex_unlock(&start_mutex);
}
+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
+ schedule_work(&cookie_work);
+}
+
// Retrieve full name from proc/pid/cmdline for java processes on Android
static int translate_app_process(char** text, int cpu, struct task_struct * task, struct vm_area_struct *vma, bool in_interrupt)
{
@@ -162,7 +170,8 @@ static int translate_app_process(char** text, int cpu, struct task_struct * task
translate_buffer_write_int(cpu, (unsigned int)task);
translate_buffer_write_int(cpu, (unsigned int)vma);
- schedule_work(&cookie_work);
+
+ mod_timer(&app_process_wake_up_timer, jiffies + 1);
goto out;
}
@@ -372,6 +381,8 @@ static int cookies_initialize(void)
gator_crc32_table[i] = crc;
}
+ setup_timer(&app_process_wake_up_timer, app_process_wake_up_handler, 0);
+
cookie_setup_error:
return err;
}
@@ -396,6 +407,7 @@ static void cookies_release(void)
per_cpu(translate_text, cpu) = NULL;
}
+ del_timer_sync(&app_process_wake_up_timer);
kfree(gator_crc32_table);
gator_crc32_table = NULL;
}
diff --git a/driver/gator_ebs.c b/driver/gator_ebs.c
index 1208d69..6abdfa4 100644
--- a/driver/gator_ebs.c
+++ b/driver/gator_ebs.c
@@ -23,10 +23,8 @@ extern unsigned long pmnc_event[];
extern unsigned long pmnc_count[];
extern unsigned long pmnc_key[];
-static DEFINE_PER_CPU(struct perf_event *, pevent);
static DEFINE_PER_CPU(struct perf_event_attr *, pevent_attr);
static DEFINE_PER_CPU(int, key);
-static DEFINE_PER_CPU(unsigned int, prev_value);
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
static void ebs_overflow_handler(struct perf_event *event, int unused, struct perf_sample_data *data, struct pt_regs *regs)
@@ -36,7 +34,7 @@ static void ebs_overflow_handler(struct perf_event *event, struct perf_sample_da
{
int cpu = smp_processor_id();
- if (event != per_cpu(pevent, cpu))
+ if (event != per_cpu(pevent_ebs, cpu))
return;
// Output backtrace
@@ -54,9 +52,9 @@ static void gator_event_sampling_online_dispatch(int cpu)
return;
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
- ev = per_cpu(pevent, cpu) = perf_event_create_kernel_counter(per_cpu(pevent_attr, cpu), cpu, 0, ebs_overflow_handler);
+ ev = perf_event_create_kernel_counter(per_cpu(pevent_attr, cpu), cpu, 0, ebs_overflow_handler);
#else
- ev = per_cpu(pevent, cpu) = perf_event_create_kernel_counter(per_cpu(pevent_attr, cpu), cpu, 0, ebs_overflow_handler, 0);
+ ev = perf_event_create_kernel_counter(per_cpu(pevent_attr, cpu), cpu, 0, ebs_overflow_handler, 0);
#endif
if (IS_ERR(ev)) {
@@ -71,7 +69,7 @@ static void gator_event_sampling_online_dispatch(int cpu)
}
ev->pmu->read(ev);
- per_cpu(prev_value, cpu) = local64_read(&ev->count);
+ per_cpu(pevent_ebs, cpu) = ev;
}
static void gator_event_sampling_offline_dispatch(int cpu)
@@ -79,9 +77,9 @@ static void gator_event_sampling_offline_dispatch(int cpu)
struct perf_event * pe = NULL;
mutex_lock(&perf_mutex);
- if (per_cpu(pevent, cpu)) {
- pe = per_cpu(pevent, cpu);
- per_cpu(pevent, cpu) = NULL;
+ if (per_cpu(pevent_ebs, cpu)) {
+ pe = per_cpu(pevent_ebs, cpu);
+ per_cpu(pevent_ebs, cpu) = NULL;
}
mutex_unlock(&perf_mutex);
@@ -95,7 +93,7 @@ static int gator_event_sampling_start(void)
int cnt, event = 0, count = 0, ebs_key = 0, cpu;
for_each_present_cpu(cpu) {
- per_cpu(pevent, cpu) = NULL;
+ per_cpu(pevent_ebs, cpu) = NULL;
per_cpu(pevent_attr, cpu) = NULL;
}
diff --git a/driver/gator_events_mali.c b/driver/gator_events_mali_400.c
index 21a6324..ef4cc58 100644
--- a/driver/gator_events_mali.c
+++ b/driver/gator_events_mali_400.c
@@ -14,6 +14,9 @@
#include "linux/mali_linux_trace.h"
+#include "gator_events_mali_common.h"
+#include "gator_events_mali_400.h"
+
/*
* There are (currently) three different variants of the comms between gator and Mali:
* 1 (deprecated): No software counter support
@@ -27,11 +30,6 @@
#define GATOR_MALI_INTERFACE_STYLE (3)
#endif
-#define MALI_200 (0x0a07)
-#define MALI_300 (0x0b06) //This is not actually true; Mali-300 is also 0x0b07
-#define MALI_400 (0x0b07)
-#define MALI_T6xx (0x0056)
-
/*
* List of possible actions allowing DDK to be controlled by Streamline.
* The following numbers are used by DDK to control the frame buffer dumping.
@@ -44,13 +42,14 @@
/*
* Check that the MALI_SUPPORT define is set to one of the allowable device codes.
*/
-#if !defined(MALI_SUPPORT)
-#error MALI_SUPPORT not defined!
-#elif (MALI_SUPPORT != MALI_200) && (MALI_SUPPORT != MALI_300) && (MALI_SUPPORT != MALI_400) && (MALI_SUPPORT != MALI_T6xx)
-#error MALI_SUPPORT set to an invalid device code
+#if (MALI_SUPPORT != MALI_400)
+#error MALI_SUPPORT set to an invalid device code: expecting MALI_400
#endif
-static const char *mali_name;
+/*
+ * The number of fragment processors. Update to suit your hardware implementation.
+ */
+#define NUM_FP_UNITS (4)
enum counters {
/* Timeline activity */
@@ -123,7 +122,9 @@ enum counters {
COUNTER_GLES_STRIP_LINES_COUNT,
COUNTER_GLES_LOOP_LINES_COUNT,
- COUNTER_FILMSTRIP,
+ COUNTER_FILMSTRIP,
+ COUNTER_FREQUENCY,
+ COUNTER_VOLTAGE,
NUMBER_OF_EVENTS
};
@@ -138,7 +139,7 @@ enum counters {
#define LAST_SW_COUNTER COUNTER_GLES_LOOP_LINES_COUNT
#define FIRST_SPECIAL_COUNTER COUNTER_FILMSTRIP
-#define LAST_SPECIAL_COUNTER COUNTER_FILMSTRIP
+#define LAST_SPECIAL_COUNTER COUNTER_VOLTAGE
/* gatorfs variables for counter enable state,
* the event the counter should count and the
@@ -168,13 +169,13 @@ static int trace_registered;
*/
static u32 get_difference(u32 start, u32 end)
{
- if (start - end >= 0)
- {
- return start - end;
- }
+ if (start - end >= 0)
+ {
+ return start - end;
+ }
- // Mali counters are unsigned 32 bit values that wrap.
- return (4294967295u - end) + start;
+ // Mali counters are unsigned 32 bit values that wrap.
+ return (4294967295u - end) + start;
}
/**
@@ -194,6 +195,7 @@ static inline int is_hw_counter(unsigned int event_id)
return (event_id >= FIRST_HW_COUNTER && event_id <= LAST_HW_COUNTER);
}
+#if GATOR_MALI_INTERFACE_STYLE == 2
/**
* Returns non-zero if the given counter ID is a software counter.
*/
@@ -201,7 +203,9 @@ static inline int is_sw_counter(unsigned int event_id)
{
return (event_id >= FIRST_SW_COUNTER && event_id <= LAST_SW_COUNTER);
}
+#endif
+#if GATOR_MALI_INTERFACE_STYLE == 2
/*
* The Mali DDK uses s64 types to contain software counter values, but gator
* can only use a maximum of 32 bits. This function scales a software counter
@@ -223,6 +227,7 @@ static u32 scale_sw_counter_value(unsigned int event_id, signed long long value)
return scaled_value;
}
+#endif
/* Probe for continuously sampled counter */
#if 0 //WE_DONT_CURRENTLY_USE_THIS_SO_SUPPRESS_WARNING
@@ -263,33 +268,25 @@ GATOR_DEFINE_PROBE(mali_sw_counter, TP_PROTO(unsigned int event_id, signed long
#if GATOR_MALI_INTERFACE_STYLE == 3
GATOR_DEFINE_PROBE(mali_sw_counters, TP_PROTO(pid_t pid, pid_t tid, void * surface_id, unsigned int * counters))
{
- u32 i;
-
- /* Copy over the values for those counters which are enabled. */
- for(i=FIRST_SW_COUNTER; i <= LAST_SW_COUNTER; i++)
- {
- if(counter_enabled[i])
- {
- counter_data[i] = (u32)(counters[i - FIRST_SW_COUNTER]);
- }
- }
-}
-#endif /* GATOR_MALI_INTERFACE_STYLE == 3 */
+ u32 i;
-//TODO need to work out how many fp units we have
-u32 gator_mali_get_n_fp(void) {
- return 4;
-}
-
-//TODO need to work out what kind of Mali we are looking at
-u32 gator_mali_get_id(void) {
- return MALI_SUPPORT;
+ /* Copy over the values for those counters which are enabled. */
+ for(i=FIRST_SW_COUNTER; i <= LAST_SW_COUNTER; i++)
+ {
+ if(counter_enabled[i])
+ {
+ counter_data[i] = (u32)(counters[i - FIRST_SW_COUNTER]);
+ }
+ }
}
+#endif /* GATOR_MALI_INTERFACE_STYLE == 3 */
-int gator_events_mali_create_files(struct super_block *sb, struct dentry *root) {
+static int create_files(struct super_block *sb, struct dentry *root) {
struct dentry *dir;
int event;
- int n_fp = gator_mali_get_n_fp();
+ int n_fp = NUM_FP_UNITS;
+
+ const char* mali_name = gator_mali_get_mali_name();
/*
* Create the filesystem entries for vertex processor, fragement processor
@@ -381,12 +378,27 @@ int gator_events_mali_create_files(struct super_block *sb, struct dentry *root)
gatorfs_create_ro_ulong(sb, dir, "key", &counter_key[event]);
}
- /* Now set up the special counter entries */
+ /* Now set up the special counter entries */
for (event = FIRST_SPECIAL_COUNTER; event <= LAST_SPECIAL_COUNTER; event++)
{
char buf[40];
- snprintf(buf, sizeof(buf), "ARM_%s_Filmstrip", mali_name);
+ switch(event) {
+ case COUNTER_FILMSTRIP:
+ snprintf(buf, sizeof(buf), "ARM_%s_Filmstrip", mali_name);
+ break;
+
+ case COUNTER_FREQUENCY:
+ snprintf(buf, sizeof(buf), "ARM_%s_Frequency", mali_name);
+ break;
+
+ case COUNTER_VOLTAGE:
+ snprintf(buf, sizeof(buf), "ARM_%s_Voltage", mali_name);
+ break;
+
+ default:
+ break;
+ }
dir = gatorfs_mkdir(sb, root, buf);
@@ -399,17 +411,14 @@ int gator_events_mali_create_files(struct super_block *sb, struct dentry *root)
gatorfs_create_ro_ulong(sb, dir, "key", &counter_key[event]);
}
-
return 0;
}
-//TODO
-void _mali_profiling_set_event(unsigned int, unsigned int);
-void _mali_osk_fb_control_set(unsigned int, unsigned int);
-void _mali_profiling_control(unsigned int, unsigned int);
-
-void _mali_profiling_get_counters(unsigned int*, unsigned int*, unsigned int*, unsigned int*);
-void (*_mali_profiling_get_counters_function_pointer)(unsigned int*, unsigned int*, unsigned int*, unsigned int*);
+/*
+ * 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;
/*
* Examine list of software counters and determine if any one is enabled.
@@ -417,17 +426,17 @@ void (*_mali_profiling_get_counters_function_pointer)(unsigned int*, unsigned in
*/
static int is_any_sw_counter_enabled(void)
{
- unsigned int i;
+ unsigned int i;
- for (i = FIRST_SW_COUNTER; i <= LAST_SW_COUNTER; i++)
- {
- if (counter_enabled[i])
- {
- return 1; /* At least one counter is enabled */
- }
- }
+ for (i = FIRST_SW_COUNTER; i <= LAST_SW_COUNTER; i++)
+ {
+ if (counter_enabled[i])
+ {
+ return 1; /* At least one counter is enabled */
+ }
+ }
- return 0; /* No s/w counters enabled */
+ return 0; /* No s/w counters enabled */
}
static void mali_counter_initialize(void)
@@ -436,22 +445,22 @@ static void mali_counter_initialize(void)
* then we can request the HW counters (of which there are only 2)
* be configured to count the desired events
*/
- void (*set_hw_event)(unsigned int, unsigned int);
- void (*set_fb_event)(unsigned int, unsigned int);
- void (*mali_control)(unsigned int, unsigned int);
+ mali_profiling_set_event_type *mali_set_hw_event;
+ mali_osk_fb_control_set_type *mali_set_fb_event;
+ mali_profiling_control_type *mali_control;
- set_hw_event = symbol_get(_mali_profiling_set_event);
+ mali_set_hw_event = symbol_get(_mali_profiling_set_event);
- if (set_hw_event) {
+ if (mali_set_hw_event) {
int i;
- pr_debug("gator: mali online _mali_profiling_set_event symbol @ %p\n",set_hw_event);
+ pr_debug("gator: mali online _mali_profiling_set_event symbol @ %p\n",mali_set_hw_event);
for (i = FIRST_HW_COUNTER; i <= LAST_HW_COUNTER; i++) {
if (counter_enabled[i]) {
- set_hw_event(i, counter_event[i]);
+ mali_set_hw_event(i, counter_event[i]);
} else {
- set_hw_event(i, 0xFFFFFFFF);
+ mali_set_hw_event(i, 0xFFFFFFFF);
}
}
@@ -460,64 +469,64 @@ static void mali_counter_initialize(void)
printk("gator: mali online _mali_profiling_set_event symbol not found\n");
}
- set_fb_event = symbol_get(_mali_osk_fb_control_set);
+ mali_set_fb_event = symbol_get(_mali_osk_fb_control_set);
- if (set_fb_event) {
- pr_debug("gator: mali online _mali_osk_fb_control_set symbol @ %p\n", set_fb_event);
+ if (mali_set_fb_event) {
+ pr_debug("gator: mali online _mali_osk_fb_control_set symbol @ %p\n", mali_set_fb_event);
- set_fb_event(0,(counter_enabled[COUNTER_FILMSTRIP]?1:0));
+ mali_set_fb_event(0,(counter_enabled[COUNTER_FILMSTRIP]?1:0));
- symbol_put(_mali_osk_fb_control_set);
- } else {
- printk("gator: mali online _mali_osk_fb_control_set symbol not found\n");
- }
+ symbol_put(_mali_osk_fb_control_set);
+ } else {
+ printk("gator: mali online _mali_osk_fb_control_set symbol not found\n");
+ }
- /* Generic control interface for Mali DDK. */
- mali_control = symbol_get(_mali_profiling_control);
- if (mali_control) {
- /* The event attribute in the XML file keeps the actual frame rate. */
- unsigned int rate = counter_event[COUNTER_FILMSTRIP] & 0xff;
- unsigned int resize_factor = (counter_event[COUNTER_FILMSTRIP] >> 8) & 0xff;
+ /* Generic control interface for Mali DDK. */
+ mali_control = symbol_get(_mali_profiling_control);
+ if (mali_control) {
+ /* The event attribute in the XML file keeps the actual frame rate. */
+ unsigned int rate = counter_event[COUNTER_FILMSTRIP] & 0xff;
+ unsigned int resize_factor = (counter_event[COUNTER_FILMSTRIP] >> 8) & 0xff;
- pr_debug("gator: mali online _mali_profiling_control symbol @ %p\n", mali_control);
+ pr_debug("gator: mali online _mali_profiling_control symbol @ %p\n", mali_control);
- mali_control(SW_EVENTS_ENABLE, (is_any_sw_counter_enabled()?1:0));
- mali_control(FBDUMP_CONTROL_ENABLE, (counter_enabled[COUNTER_FILMSTRIP]?1:0));
- mali_control(FBDUMP_CONTROL_RATE, rate);
- mali_control(FBDUMP_CONTROL_RESIZE_FACTOR, resize_factor);
+ mali_control(SW_EVENTS_ENABLE, (is_any_sw_counter_enabled()?1:0));
+ mali_control(FBDUMP_CONTROL_ENABLE, (counter_enabled[COUNTER_FILMSTRIP]?1:0));
+ mali_control(FBDUMP_CONTROL_RATE, rate);
+ mali_control(FBDUMP_CONTROL_RESIZE_FACTOR, resize_factor);
- pr_debug("gator: sent mali_control enabled=%d, rate=%d\n", (counter_enabled[COUNTER_FILMSTRIP]?1:0), rate);
+ pr_debug("gator: sent mali_control enabled=%d, rate=%d\n", (counter_enabled[COUNTER_FILMSTRIP]?1:0), rate);
- symbol_put(_mali_profiling_control);
- } else {
- printk("gator: mali online _mali_profiling_control symbol not found\n");
- }
+ symbol_put(_mali_profiling_control);
+ } else {
+ printk("gator: mali online _mali_profiling_control symbol not found\n");
+ }
- _mali_profiling_get_counters_function_pointer = symbol_get(_mali_profiling_get_counters);
- if (_mali_profiling_get_counters_function_pointer){
- pr_debug("gator: mali online _mali_profiling_get_counters symbol @ %p\n", _mali_profiling_get_counters_function_pointer);
- counter_prev[COUNTER_L2_C0] = 0;
- counter_prev[COUNTER_L2_C1] = 0;
- }
- else{
- pr_debug("gator WARNING: mali _mali_profiling_get_counters symbol not defined");
- }
+ mali_get_counters = symbol_get(_mali_profiling_get_counters);
+ if (mali_get_counters){
+ pr_debug("gator: mali online _mali_profiling_get_counters symbol @ %p\n", mali_get_counters);
+ counter_prev[COUNTER_L2_C0] = 0;
+ counter_prev[COUNTER_L2_C1] = 0;
+ }
+ else{
+ pr_debug("gator WARNING: mali _mali_profiling_get_counters symbol not defined");
+ }
}
static void mali_counter_deinitialize(void)
{
- void (*set_hw_event)(unsigned int, unsigned int);
- void (*set_fb_event)(unsigned int, unsigned int);
- void (*mali_control)(unsigned int, unsigned int);
+ mali_profiling_set_event_type *mali_set_hw_event;
+ mali_osk_fb_control_set_type *mali_set_fb_event;
+ mali_profiling_control_type *mali_control;
- set_hw_event = symbol_get(_mali_profiling_set_event);
+ mali_set_hw_event = symbol_get(_mali_profiling_set_event);
- if (set_hw_event) {
+ if (mali_set_hw_event) {
int i;
- pr_debug("gator: mali offline _mali_profiling_set_event symbol @ %p\n",set_hw_event);
+ 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++) {
- set_hw_event(i, 0xFFFFFFFF);
+ mali_set_hw_event(i, 0xFFFFFFFF);
}
symbol_put(_mali_profiling_set_event);
@@ -525,41 +534,41 @@ static void mali_counter_deinitialize(void)
printk("gator: mali offline _mali_profiling_set_event symbol not found\n");
}
- set_fb_event = symbol_get(_mali_osk_fb_control_set);
+ mali_set_fb_event = symbol_get(_mali_osk_fb_control_set);
- if (set_fb_event) {
- pr_debug("gator: mali offline _mali_osk_fb_control_set symbol @ %p\n", set_fb_event);
+ if (mali_set_fb_event) {
+ pr_debug("gator: mali offline _mali_osk_fb_control_set symbol @ %p\n", mali_set_fb_event);
- set_fb_event(0,0);
+ mali_set_fb_event(0,0);
- symbol_put(_mali_osk_fb_control_set);
- } else {
- printk("gator: mali offline _mali_osk_fb_control_set symbol not found\n");
- }
-
- /* Generic control interface for Mali DDK. */
- mali_control = symbol_get(_mali_profiling_control);
+ symbol_put(_mali_osk_fb_control_set);
+ } else {
+ printk("gator: mali offline _mali_osk_fb_control_set symbol not found\n");
+ }
+
+ /* Generic control interface for Mali DDK. */
+ mali_control = symbol_get(_mali_profiling_control);
- if (mali_control) {
- pr_debug("gator: mali offline _mali_profiling_control symbol @ %p\n", set_fb_event);
+ if (mali_control) {
+ pr_debug("gator: mali offline _mali_profiling_control symbol @ %p\n", mali_set_fb_event);
- /* Reset the DDK state - disable counter collection */
- mali_control(SW_EVENTS_ENABLE, 0);
+ /* Reset the DDK state - disable counter collection */
+ mali_control(SW_EVENTS_ENABLE, 0);
- mali_control(FBDUMP_CONTROL_ENABLE, 0);
+ mali_control(FBDUMP_CONTROL_ENABLE, 0);
- symbol_put(_mali_profiling_control);
- } else {
- printk("gator: mali offline _mali_profiling_control symbol not found\n");
- }
+ symbol_put(_mali_profiling_control);
+ } else {
+ printk("gator: mali offline _mali_profiling_control symbol not found\n");
+ }
- if (_mali_profiling_get_counters_function_pointer){
- symbol_put(_mali_profiling_get_counters);
- }
+ if (mali_get_counters){
+ symbol_put(_mali_profiling_get_counters);
+ }
}
-static int gator_events_mali_start(void) {
+static int start(void) {
// register tracepoints
if (GATOR_REGISTER_TRACE(mali_hw_counter)) {
printk("gator: mali_hw_counter tracepoint failed to activate\n");
@@ -567,9 +576,9 @@ static int gator_events_mali_start(void) {
}
#if GATOR_MALI_INTERFACE_STYLE == 1
- /* None. */
+ /* None. */
#elif GATOR_MALI_INTERFACE_STYLE == 2
- /* For patched Mali driver. */
+ /* For patched Mali driver. */
if (GATOR_REGISTER_TRACE(mali_sw_counter)) {
printk("gator: mali_sw_counter tracepoint failed to activate\n");
return -1;
@@ -590,7 +599,7 @@ static int gator_events_mali_start(void) {
return 0;
}
-static void gator_events_mali_stop(void) {
+static void stop(void) {
unsigned int cnt;
pr_debug("gator: mali stop\n");
@@ -624,7 +633,7 @@ static void gator_events_mali_stop(void) {
mali_counter_deinitialize();
}
-static int gator_events_mali_read(int **buffer) {
+static int read(int **buffer) {
int cnt, len = 0;
if (smp_processor_id()) return 0;
@@ -637,8 +646,8 @@ static int gator_events_mali_read(int **buffer) {
u32 val1 = 0;
// Poke the driver to get the counter values
- if (_mali_profiling_get_counters_function_pointer){
- _mali_profiling_get_counters_function_pointer(&src0, &val0, &src1, &val1);
+ if (mali_get_counters){
+ mali_get_counters(&src0, &val0, &src1, &val1);
}
if (counter_enabled[COUNTER_L2_C0])
@@ -670,6 +679,23 @@ static int gator_events_mali_read(int **buffer) {
}
}
+ /*
+ * 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]) {
+ counter_dump[len++] = counter_key[cnt];
+ counter_dump[len++] = counter_data[cnt];
+ }
+
+ cnt = COUNTER_VOLTAGE;
+ if (counter_enabled[cnt]) {
+ counter_dump[len++] = counter_key[cnt];
+ counter_dump[len++] = counter_data[cnt];
+ }
+
+
if (buffer) {
*buffer = (int*) counter_dump;
}
@@ -678,34 +704,20 @@ static int gator_events_mali_read(int **buffer) {
}
static struct gator_interface gator_events_mali_interface = {
- .create_files = gator_events_mali_create_files,
- .start = gator_events_mali_start,
- .stop = gator_events_mali_stop,
- .read = gator_events_mali_read,
+ .create_files = create_files,
+ .start = start,
+ .stop = stop,
+ .read = read,
};
+extern void gator_events_mali_log_dvfs_event(unsigned int frequency_mhz, unsigned int voltage_mv) {
+ counter_data[COUNTER_FREQUENCY] = frequency_mhz;
+ counter_data[COUNTER_VOLTAGE] = voltage_mv;
+}
+
int gator_events_mali_init(void)
{
unsigned int cnt;
- u32 id = gator_mali_get_id();
-
- switch (id) {
- case MALI_T6xx:
- mali_name = "Mali-T6xx";
- break;
- case MALI_400:
- mali_name = "Mali-400";
- break;
- case MALI_300:
- mali_name = "Mali-300";
- break;
- case MALI_200:
- mali_name = "Mali-200";
- break;
- default:
- printk("Unknown Mali ID (%d)\n", id);
- return -1;
- }
pr_debug("gator: mali init\n");
@@ -714,11 +726,12 @@ int gator_events_mali_init(void)
counter_event[cnt] = 0;
counter_key[cnt] = gator_events_get_key();
counter_address[cnt] = NULL;
- counter_data[cnt] = 0;
+ counter_data[cnt] = 0;
}
trace_registered = 0;
return gator_events_install(&gator_events_mali_interface);
}
+
gator_events_init(gator_events_mali_init);
diff --git a/driver/gator_events_mali_400.h b/driver/gator_events_mali_400.h
new file mode 100644
index 0000000..b784ae9
--- /dev/null
+++ b/driver/gator_events_mali_400.h
@@ -0,0 +1,19 @@
+/*
+ * This confidential and proprietary software may be used only as
+ * authorised by a licensing agreement from ARM Limited
+ * (C) COPYRIGHT 2011-2012 ARM Limited
+ * ALL RIGHTS RESERVED
+ * The entire notice above must be reproduced on all authorised
+ * copies and copies may only be made to the extent permitted
+ * by a licensing agreement from ARM Limited.
+ */
+
+/*
+ * Header contains common definitions for the Mali-400 processors.
+ */
+#if !defined(GATOR_EVENTS_MALI_400_H)
+#define GATOR_EVENTS_MALI_400_H
+
+extern void gator_events_mali_log_dvfs_event(unsigned int d0, unsigned int d1);
+
+#endif /* GATOR_EVENTS_MALI_400_H */
diff --git a/driver/gator_events_mali_common.c b/driver/gator_events_mali_common.c
new file mode 100644
index 0000000..2dd9ad6
--- /dev/null
+++ b/driver/gator_events_mali_common.c
@@ -0,0 +1,79 @@
+/*
+ * This confidential and proprietary software may be used only as
+ * authorised by a licensing agreement from ARM Limited
+ * (C) COPYRIGHT 2011-2012 ARM Limited
+ * ALL RIGHTS RESERVED
+ * The entire notice above must be reproduced on all authorised
+ * copies and copies may only be made to the extent permitted
+ * by a licensing agreement from ARM Limited.
+ */
+#include "gator_events_mali_common.h"
+
+static u32 gator_mali_get_id(void)
+{
+ return MALI_SUPPORT;
+}
+
+extern const char* gator_mali_get_mali_name(void)
+{
+ u32 id = gator_mali_get_id();
+
+ switch (id) {
+ case MALI_T6xx:
+ return "Mali-T6xx";
+ case MALI_400:
+ return "Mali-400";
+ default:
+ pr_debug("gator: Mali-T6xx: unknown Mali ID (%d)\n", id);
+ return "Mali-Unknown";
+ }
+}
+
+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)
+{
+ int err;
+ char buf[255];
+ struct dentry *dir;
+
+ /* 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);
+
+ dir = gatorfs_mkdir(sb, root, buf);
+
+ if (dir == NULL)
+ {
+ pr_debug("gator: Mali-T6xx: error creating file system for: %s (%s)", event_name, buf);
+ return -1;
+ }
+
+ err = gatorfs_create_ulong(sb, dir, "enabled", &counter->enabled);
+ if (err != 0)
+ {
+ pr_debug("gator: Mali-T6xx: error calling gatorfs_create_ulong for: %s (%s)", event_name, buf);
+ return -1;
+ }
+ err = gatorfs_create_ro_ulong(sb, dir, "key", &counter->key);
+ if (err != 0)
+ {
+ pr_debug("gator: Mali-T6xx: error calling gatorfs_create_ro_ulong for: %s (%s)", event_name, buf);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+extern void gator_mali_initialise_counters(mali_counter counters[], unsigned int n_counters)
+{
+ unsigned int cnt;
+
+ for (cnt = 0; cnt < n_counters; cnt++) {
+ mali_counter *counter = &counters[cnt];
+
+ counter->key = gator_events_get_key();
+ counter->enabled = 0;
+ }
+}
diff --git a/driver/gator_events_mali_common.h b/driver/gator_events_mali_common.h
new file mode 100644
index 0000000..cb851d5
--- /dev/null
+++ b/driver/gator_events_mali_common.h
@@ -0,0 +1,85 @@
+/*
+ * This confidential and proprietary software may be used only as
+ * authorised by a licensing agreement from ARM Limited
+ * (C) COPYRIGHT 2011-2012 ARM Limited
+ * ALL RIGHTS RESERVED
+ * The entire notice above must be reproduced on all authorised
+ * copies and copies may only be made to the extent permitted
+ * by a licensing agreement from ARM Limited.
+ */
+#if !defined(GATOR_EVENTS_MALI_COMMON_H)
+#define GATOR_EVENTS_MALI_COMMON_H
+
+#include "gator.h"
+
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/math64.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+
+/* Device codes for each known GPU */
+#define MALI_400 (0x0b07)
+#define MALI_T6xx (0x0056)
+
+/* Ensure that MALI_SUPPORT has been defined to something. */
+#ifndef MALI_SUPPORT
+#error MALI_SUPPORT not defined!
+#endif
+
+/* Values for the supported activity event types */
+#define ACTIVITY_START (1)
+#define ACTIVITY_STOP (2)
+
+/*
+ * Runtime state information for a counter.
+ */
+typedef struct {
+ unsigned long key; /* 'key' (a unique id set by gatord and returned by gator.ko) */
+ unsigned long enabled; /* counter enable state */
+} mali_counter;
+
+typedef void mali_profiling_set_event_type(unsigned int, unsigned int);
+typedef void mali_osk_fb_control_set_type(unsigned int, unsigned 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.
+ */
+extern void _mali_profiling_set_event(unsigned int, unsigned int);
+extern void _mali_osk_fb_control_set(unsigned int, unsigned int);
+extern void _mali_profiling_control(unsigned int, unsigned int);
+extern void _mali_profiling_get_counters(unsigned int*, unsigned int*, unsigned int*, unsigned int*);
+
+/**
+ * Returns a name which identifies the GPU type (eg Mali-400, Mali-T6xx).
+ *
+ * @return The name as a constant string.
+ */
+extern const char* gator_mali_get_mali_name(void);
+
+/**
+ * Creates a filesystem entry under /dev/gator relating to the specified event name and key, and
+ * associate the key/enable values with this entry point.
+ *
+ * @param mali_name A name related to the type of GPU, obtained from a call to gator_mali_get_mali_name()
+ * @param event_name The name of the event.
+ * @param sb Linux super block
+ * @param root Directory under which the entry will be created.
+ * @param counter_key Ptr to location which will be associated with the counter key.
+ * @param counter_enabled Ptr to location which will be associated with the counter enable state.
+ *
+ * @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);
+
+/**
+ * Initialises the counter array.
+ *
+ * @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);
+
+#endif /* GATOR_EVENTS_MALI_COMMON_H */
diff --git a/driver/gator_events_mali_t6xx.c b/driver/gator_events_mali_t6xx.c
new file mode 100644
index 0000000..79af764
--- /dev/null
+++ b/driver/gator_events_mali_t6xx.c
@@ -0,0 +1,553 @@
+/*
+ * This confidential and proprietary software may be used only as
+ * authorised by a licensing agreement from ARM Limited
+ * (C) COPYRIGHT 2011 ARM Limited
+ * ALL RIGHTS RESERVED
+ * The entire notice above must be reproduced on all authorised
+ * copies and copies may only be made to the extent permitted
+ * by a licensing agreement from ARM Limited.
+ */
+
+#include "gator.h"
+
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/math64.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+
+#include "linux/mali_linux_trace.h"
+
+
+#include "gator_events_mali_common.h"
+
+/*
+ * 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
+#endif
+
+
+/* Counters for Mali-T6xx:
+ *
+ * - Timeline events
+ * They are tracepoints, but instead of reporting a number they report a START/STOP event.
+ * They are reported in Streamline as number of microseconds while that particular counter was active.
+ *
+ * - SW counters
+ * They are tracepoints reporting a particular number.
+ * They are accumulated in sw_counter_data array until they are passed to Streamline, then they are zeroed.
+ *
+ * - Accumulators
+ * They are the same as software counters but their value is not zeroed.
+ */
+
+/* Timeline (start/stop) activity */
+static const char* timeline_event_names [] =
+{
+ "PM_SHADER_0",
+ "PM_SHADER_1",
+ "PM_SHADER_2",
+ "PM_SHADER_3",
+ "PM_SHADER_4",
+ "PM_SHADER_5",
+ "PM_SHADER_6",
+ "PM_SHADER_7",
+ "PM_TILER_0",
+ "PM_L2_0",
+ "PM_L2_1",
+ "MMU_AS_0",
+ "MMU_AS_1",
+ "MMU_AS_2",
+ "MMU_AS_3"
+};
+
+enum
+{
+ PM_SHADER_0 = 0,
+ PM_SHADER_1,
+ PM_SHADER_2,
+ PM_SHADER_3,
+ PM_SHADER_4,
+ PM_SHADER_5,
+ PM_SHADER_6,
+ PM_SHADER_7,
+ PM_TILER_0,
+ PM_L2_0,
+ PM_L2_1,
+ MMU_AS_0,
+ MMU_AS_1,
+ MMU_AS_2,
+ MMU_AS_3
+};
+/* The number of shader blocks in the enum above */
+#define NUM_PM_SHADER (8)
+
+/* Software Counters */
+static const char* software_counter_names [] =
+{
+ "MMU_PAGE_FAULT_0",
+ "MMU_PAGE_FAULT_1",
+ "MMU_PAGE_FAULT_2",
+ "MMU_PAGE_FAULT_3"
+};
+
+enum
+{
+ MMU_PAGE_FAULT_0 = 0,
+ MMU_PAGE_FAULT_1,
+ MMU_PAGE_FAULT_2,
+ MMU_PAGE_FAULT_3
+};
+
+/* Software Counters */
+static const char* accumulators_names [] =
+{
+ "TOTAL_ALLOC_PAGES"
+};
+
+enum
+{
+ TOTAL_ALLOC_PAGES = 0
+};
+
+#define FIRST_TIMELINE_EVENT (0)
+#define NUMBER_OF_TIMELINE_EVENTS (sizeof(timeline_event_names) / sizeof(timeline_event_names[0]))
+#define FIRST_SOFTWARE_COUNTER (FIRST_TIMELINE_EVENT + NUMBER_OF_TIMELINE_EVENTS)
+#define NUMBER_OF_SOFTWARE_COUNTERS (sizeof(software_counter_names) / sizeof(software_counter_names[0]))
+#define FIRST_ACCUMULATOR (FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS)
+#define NUMBER_OF_ACCUMULATORS (sizeof(accumulators_names) / sizeof(accumulators_names[0]))
+#define NUMBER_OF_EVENTS (NUMBER_OF_TIMELINE_EVENTS + NUMBER_OF_SOFTWARE_COUNTERS + NUMBER_OF_ACCUMULATORS)
+
+/*
+ * gatorfs variables for counter enable state
+ */
+static mali_counter counters[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];
+
+/*
+ * 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];
+
+/* The data we have recorded */
+static unsigned int timeline_data[NUMBER_OF_TIMELINE_EVENTS];
+static unsigned int sw_counter_data[NUMBER_OF_SOFTWARE_COUNTERS];
+static unsigned int accumulators_data[NUMBER_OF_ACCUMULATORS];
+
+/* Hold the previous timestamp, used to calculate the sample interval. */
+static struct timespec prev_timestamp;
+
+/**
+ * Returns the timespan (in microseconds) between the two specified timestamps.
+ *
+ * @param start Ptr to the start timestamp
+ * @param end Ptr to the end timestamp
+ *
+ * @return Number of microseconds between the two timestamps (can be negative if start follows end).
+ */
+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;
+}
+
+static void record_timeline_event(unsigned int timeline_index, unsigned int type)
+{
+ struct timespec event_timestamp;
+ struct timespec *event_start = &timeline_event_starttime[timeline_index];
+
+ switch(type)
+ {
+ case ACTIVITY_START:
+ /* Get the event time... */
+ getnstimeofday(&event_timestamp);
+
+ /* Remember the start time if the activity is not already started */
+ if(event_start->tv_sec == 0)
+ {
+ *event_start = event_timestamp; /* Structure copy */
+ }
+ break;
+
+ case ACTIVITY_STOP:
+ /* if the counter was started... */
+ if(event_start->tv_sec != 0)
+ {
+ /* Get the event time... */
+ getnstimeofday(&event_timestamp);
+
+ /* Accumulate the duration in us */
+ timeline_data[timeline_index] += get_duration_us(event_start, &event_timestamp);
+
+ /* Reset the start time to indicate the activity is stopped. */
+ event_start->tv_sec = 0;
+ }
+ break;
+
+ default:
+ /* Other activity events are ignored. */
+ break;
+ }
+}
+
+/*
+ * Documentation about the following tracepoints is in mali_linux_trace.h
+ */
+
+GATOR_DEFINE_PROBE(mali_pm_status, TP_PROTO(unsigned int event_id, unsigned long long value))
+{
+#define SHADER_PRESENT_LO 0x100 /* (RO) Shader core present bitmap, low word */
+#define TILER_PRESENT_LO 0x110 /* (RO) Tiler core present bitmap, low word */
+#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;
+
+ switch (event_id)
+ {
+ case SHADER_PRESENT_LO:
+ {
+ unsigned long long changed_bitmask = previous_shader_bitmask ^ value;
+ int pos;
+
+ for (pos = 0; pos < NUM_PM_SHADER; ++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;
+ break;
+ }
+
+ case TILER_PRESENT_LO:
+ {
+ unsigned long long changed = previous_tiler_bitmask ^ value;
+
+ if (BIT_AT(changed, 0))
+ {
+ record_timeline_event(PM_TILER_0, BIT_AT(value, 0) ? ACTIVITY_START : ACTIVITY_STOP);
+ }
+
+ previous_tiler_bitmask = value;
+ break;
+ }
+
+ case L2_PRESENT_LO:
+ {
+ unsigned long long changed = previous_l2_bitmask ^ value;
+
+ if (BIT_AT(changed, 0))
+ {
+ record_timeline_event(PM_L2_0, BIT_AT(value, 0) ? ACTIVITY_START : ACTIVITY_STOP);
+ }
+ if (BIT_AT(changed, 4))
+ {
+ record_timeline_event(PM_L2_1, BIT_AT(value, 4) ? ACTIVITY_START : ACTIVITY_STOP);
+ }
+
+ previous_l2_bitmask = value;
+ break;
+ }
+
+ default:
+ /* No other blocks are supported at present */
+ break;
+ }
+
+#undef SHADER_PRESENT_LO
+#undef TILER_PRESENT_LO
+#undef L2_PRESENT_LO
+#undef BIT_AT
+}
+
+GATOR_DEFINE_PROBE(mali_page_fault_insert_pages, TP_PROTO(int event_id, unsigned long value))
+{
+ /* We add to the previous since we may receive many tracepoints in one sample period */
+ sw_counter_data[MMU_PAGE_FAULT_0 + event_id] += value;
+}
+
+GATOR_DEFINE_PROBE(mali_mmu_as_in_use, TP_PROTO(int event_id))
+{
+ record_timeline_event(MMU_AS_0 + event_id, ACTIVITY_START);
+}
+
+GATOR_DEFINE_PROBE(mali_mmu_as_released, TP_PROTO(int event_id))
+{
+ record_timeline_event(MMU_AS_0 + event_id, ACTIVITY_STOP);
+}
+
+GATOR_DEFINE_PROBE(mali_total_alloc_pages_change, TP_PROTO(long long int event_id))
+{
+ accumulators_data[TOTAL_ALLOC_PAGES] = event_id;
+}
+
+static int create_files(struct super_block *sb, struct dentry *root)
+{
+ int event;
+ /*
+ * Create the filesystem for all events
+ */
+ int counter_index = 0;
+ const char* mali_name = gator_mali_get_mali_name();
+
+ 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]) != 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]) != 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]) != 0)
+ {
+ return -1;
+ }
+ counter_index++;
+ }
+
+ return 0;
+}
+
+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");
+ 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");
+ 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");
+ return 0;
+ }
+
+ if (GATOR_REGISTER_TRACE(mali_mmu_as_released))
+ {
+ pr_debug("gator: Mali-T6xx: 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");
+ 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);
+
+ return 1;
+}
+
+static int start(void)
+{
+ unsigned int cnt;
+
+ /* Clean all data for the next capture */
+ for (cnt = 0; cnt < NUMBER_OF_TIMELINE_EVENTS; cnt++)
+ {
+ timeline_event_starttime[cnt].tv_sec = timeline_event_starttime[cnt].tv_nsec = 0;
+ timeline_data[cnt] = 0;
+ }
+
+ for (cnt = 0; cnt < NUMBER_OF_SOFTWARE_COUNTERS; cnt++)
+ {
+ sw_counter_data[cnt] = 0;
+ }
+
+ for (cnt = 0; cnt < NUMBER_OF_ACCUMULATORS; cnt++)
+ {
+ accumulators_data[cnt] = 0;
+ }
+
+ /* Register tracepoints */
+ if (register_tracepoints() == 0)
+ {
+ return -1;
+ }
+
+ /*
+ * Set the first timestamp for calculating the sample interval. The first interval could be quite long,
+ * since it will be the time between 'start' and the first 'read'.
+ * This means that timeline values will be divided by a big number for the first sample.
+ */
+ getnstimeofday(&prev_timestamp);
+
+ return 0;
+}
+
+static void stop(void)
+{
+ pr_debug("gator: Mali-T6xx: 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");
+
+ GATOR_UNREGISTER_TRACE(mali_page_fault_insert_pages);
+ pr_debug("gator: Mali-T6xx: 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");
+
+ GATOR_UNREGISTER_TRACE(mali_mmu_as_released);
+ pr_debug("gator: Mali-T6xx: 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");
+}
+
+static int read(int **buffer)
+{
+ int cnt;
+ int len = 0;
+ long sample_interval_us = 0;
+ struct timespec read_timestamp;
+
+ if (smp_processor_id()!=0)
+ {
+ return 0;
+ }
+
+ /* Get the start of this sample period. */
+ getnstimeofday(&read_timestamp);
+
+ /*
+ * 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) {
+ sample_interval_us = get_duration_us(&prev_timestamp, &read_timestamp);
+ }
+
+ /* Structure copy. Update the previous timestamp. */
+ prev_timestamp = read_timestamp;
+
+ /*
+ * 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];
+ 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(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. */
+ }
+
+ if(sample_interval_us != 0) {
+ /* 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");
+ value = 0;
+ }
+
+ /* Clear the counter value ready for the next sample. */
+ timeline_data[index] = 0;
+
+ counter_dump[len++] = counter->key;
+ counter_dump[len++] = value;
+ }
+ }
+
+ /* Report the software counters */
+ for (cnt = FIRST_SOFTWARE_COUNTER; cnt < (FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS); cnt++)
+ {
+ const 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 */
+ sw_counter_data[index] = 0;
+ }
+ }
+
+ /* Report the accumulators */
+ for (cnt = FIRST_ACCUMULATOR; cnt < (FIRST_ACCUMULATOR + NUMBER_OF_ACCUMULATORS); cnt++)
+ {
+ const 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 */
+ }
+ }
+
+ /* Update the buffer */
+ if (buffer)
+ {
+ *buffer = (int*) counter_dump;
+ }
+
+ return len;
+}
+
+static struct gator_interface gator_events_mali_t6xx_interface = {
+ .create_files = create_files,
+ .start = start,
+ .stop = stop,
+ .read = read
+};
+
+extern int gator_events_mali_t6xx_init(void)
+{
+ pr_debug("gator: Mali-T6xx: sw_counters init\n");
+
+ gator_mali_initialise_counters(counters, NUMBER_OF_EVENTS);
+
+ return gator_events_install(&gator_events_mali_t6xx_interface);
+}
+
+gator_events_init(gator_events_mali_t6xx_init);
diff --git a/driver/gator_events_mali_t6xx_hw.c b/driver/gator_events_mali_t6xx_hw.c
new file mode 100644
index 0000000..12ffebc
--- /dev/null
+++ b/driver/gator_events_mali_t6xx_hw.c
@@ -0,0 +1,571 @@
+/*
+ * This confidential and proprietary software may be used only as
+ * authorised by a licensing agreement from ARM Limited
+ * (C) COPYRIGHT 2011-2012 ARM Limited
+ * ALL RIGHTS RESERVED
+ * The entire notice above must be reproduced on all authorised
+ * copies and copies may only be made to the extent permitted
+ * by a licensing agreement from ARM Limited.
+ */
+
+#include "gator.h"
+
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/math64.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+
+/* Mali T6xx DDK includes */
+#include "linux/mali_linux_trace.h"
+#include "kbase/src/common/mali_kbase.h"
+#include "kbase/src/linux/mali_kbase_mem_linux.h"
+
+#include "gator_events_mali_common.h"
+
+/* Blocks for HW counters */
+enum
+{
+ JM_BLOCK = 0,
+ TILER_BLOCK,
+ SHADER_BLOCK,
+ MMU_BLOCK
+};
+
+/* Counters for Mali-T6xx:
+ *
+ * - HW counters, 4 blocks
+ * For HW counters we need strings to create /dev/gator/events files.
+ * Enums are not needed because the position of the HW name in the array is the same
+ * of the corresponding value in the received block of memory.
+ * HW counters are requested by calculating a bitmask, passed then to the driver.
+ * Every millisecond a HW counters dump is requested, and if the previous has been completed they are read.
+ */
+
+/* Hardware Counters */
+static const char* const hardware_counter_names [] =
+{
+ /* Job Manager */
+ "",
+ "",
+ "",
+ "",
+ "MESSAGES_SENT",
+ "MESSAGES_RECEIVED",
+ "GPU_ACTIVE", /* 6 */
+ "IRQ_ACTIVE",
+ "JS0_JOBS",
+ "JS0_TASKS",
+ "JS0_ACTIVE",
+ "",
+ "JS0_WAIT_READ",
+ "JS0_WAIT_ISSUE",
+ "JS0_WAIT_DEPEND",
+ "JS0_WAIT_FINISH",
+ "JS1_JOBS",
+ "JS1_TASKS",
+ "JS1_ACTIVE",
+ "",
+ "JS1_WAIT_READ",
+ "JS1_WAIT_ISSUE",
+ "JS1_WAIT_DEPEND",
+ "JS1_WAIT_FINISH",
+ "JS2_JOBS",
+ "JS2_TASKS",
+ "JS2_ACTIVE",
+ "",
+ "JS2_WAIT_READ",
+ "JS2_WAIT_ISSUE",
+ "JS2_WAIT_DEPEND",
+ "JS2_WAIT_FINISH",
+ "JS3_JOBS",
+ "JS3_TASKS",
+ "JS3_ACTIVE",
+ "",
+ "JS3_WAIT_READ",
+ "JS3_WAIT_ISSUE",
+ "JS3_WAIT_DEPEND",
+ "JS3_WAIT_FINISH",
+ "JS4_JOBS",
+ "JS4_TASKS",
+ "JS4_ACTIVE",
+ "",
+ "JS4_WAIT_READ",
+ "JS4_WAIT_ISSUE",
+ "JS4_WAIT_DEPEND",
+ "JS4_WAIT_FINISH",
+ "JS5_JOBS",
+ "JS5_TASKS",
+ "JS5_ACTIVE",
+ "",
+ "JS5_WAIT_READ",
+ "JS5_WAIT_ISSUE",
+ "JS5_WAIT_DEPEND",
+ "JS5_WAIT_FINISH",
+ "JS6_JOBS",
+ "JS6_TASKS",
+ "JS6_ACTIVE",
+ "",
+ "JS6_WAIT_READ",
+ "JS6_WAIT_ISSUE",
+ "JS6_WAIT_DEPEND",
+ "JS6_WAIT_FINISH",
+
+ /*Tiler*/
+ "",
+ "",
+ "",
+ "JOBS_PROCESSED",
+ "TRIANGLES",
+ "QUADS",
+ "POLYGONS",
+ "POINTS",
+ "LINES",
+ "VCACHE_HIT",
+ "VCACHE_MISS",
+ "FRONT_FACING",
+ "BACK_FACING",
+ "PRIM_VISIBLE",
+ "PRIM_CULLED",
+ "PRIM_CLIPPED",
+ "LEVEL0",
+ "LEVEL1",
+ "LEVEL2",
+ "LEVEL3",
+ "LEVEL4",
+ "LEVEL5",
+ "LEVEL6",
+ "LEVEL7",
+ "COMMAND_1",
+ "COMMAND_2",
+ "COMMAND_3",
+ "COMMAND_4",
+ "COMMAND_4_7",
+ "COMMAND_8_15",
+ "COMMAND_16_63",
+ "COMMAND_64",
+ "COMPRESS_IN",
+ "COMPRESS_OUT",
+ "COMPRESS_FLUSH",
+ "TIMESTAMPS",
+ "PCACHE_HIT",
+ "PCACHE_MISS",
+ "PCACHE_LINE",
+ "PCACHE_STALL",
+ "WRBUF_HIT",
+ "WRBUF_MISS",
+ "WRBUF_LINE",
+ "WRBUF_PARTIAL",
+ "WRBUF_STALL",
+ "ACTIVE",
+ "LOADING_DESC",
+ "INDEX_WAIT",
+ "INDEX_RANGE_WAIT",
+ "VERTEX_WAIT",
+ "PCACHE_WAIT",
+ "WRBUF_WAIT",
+ "BUS_READ",
+ "BUS_WRITE",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "UTLB_STALL",
+ "UTLB_REPLAY_MISS",
+ "UTLB_REPLAY_FULL",
+ "UTLB_NEW_MISS",
+ "UTLB_HIT",
+
+ /* Shader Core */
+ "",
+ "",
+ "",
+ "SHADER_CORE_ACTIVE",
+ "FRAG_ACTIVE",
+ "FRAG_PRIMATIVES",
+ "FRAG_PRIMATIVES_DROPPED",
+ "FRAG_CYCLE_DESC",
+ "FRAG_CYCLES_PLR",
+ "FRAG_CYCLES_VERT",
+ "FRAG_CYCLES_TRISETUP",
+ "FRAG_CYCLES_RAST",
+ "FRAG_THREADS",
+ "FRAG_DUMMY_THREADS",
+ "FRAG_QUADS_RAST",
+ "FRAG_QUADS_EZS_TEST",
+ "FRAG_QUADS_EZS_KILLED",
+ "FRAG_QUADS_LZS_TEST",
+ "FRAG_QUADS_LZS_KILLED",
+ "FRAG_CYCLE_NO_TILE",
+ "FRAG_NUM_TILES",
+ "FRAG_TRANS_ELIM",
+ "COMPUTE_ACTIVE",
+ "COMPUTE_TASKS",
+ "COMPUTE_THREADS",
+ "COMPUTE_CYCLES_DESC",
+ "TRIPIPE_ACTIVE",
+ "ARITH_WORDS",
+ "ARITH_CYCLES_REG",
+ "ARITH_CYCLES_L0",
+ "ARITH_FRAG_DEPEND",
+ "LS_WORDS",
+ "LS_ISSUES",
+ "LS_RESTARTS",
+ "LS_REISSUES_MISS",
+ "LS_REISSUES_VD",
+ "LS_REISSUE_ATTRIB_MISS",
+ "LS_NO_WB",
+ "TEX_WORDS",
+ "TEX_BUBBLES",
+ "TEX_WORDS_L0",
+ "TEX_WORDS_DESC",
+ "TEX_THREADS",
+ "TEX_RECIRC_FMISS",
+ "TEX_RECIRC_DESC",
+ "TEX_RECIRC_MULTI",
+ "TEX_RECIRC_PMISS",
+ "TEX_RECIRC_CONF",
+ "LSC_READ_HITS",
+ "LSC_READ_MISSES",
+ "LSC_WRITE_HITS",
+ "LSC_WRITE_MISSES",
+ "LSC_ATOMIC_HITS",
+ "LSC_ATOMIC_MISSES",
+ "LSC_LINE_FETCHES",
+ "LSC_DIRTY_LINE",
+ "LSC_SNOOPS",
+ "AXI_TLB_STALL",
+ "AXI_TLB_MIESS",
+ "AXI_TLB_TRANSACTION",
+ "LS_TLB_MISS",
+ "LS_TLB_HIT",
+ "AXI_BEATS_READ",
+ "AXI_BEATS_WRITTEN",
+
+ /*L2 and MMU */
+ "",
+ "",
+ "",
+ "",
+ "MMU_TABLE_WALK",
+ "MMU_REPLAY_MISS",
+ "MMU_REPLAY_FULL",
+ "MMU_NEW_MISS",
+ "MMU_HIT",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "UTLB_STALL",
+ "UTLB_REPLAY_MISS",
+ "UTLB_REPLAY_FULL",
+ "UTLB_NEW_MISS",
+ "UTLB_HIT",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "L2_WRITE_BEATS",
+ "L2_READ_BEATS",
+ "L2_ANY_LOOKUP",
+ "L2_READ_LOOKUP",
+ "L2_SREAD_LOOKUP",
+ "L2_READ_REPLAY",
+ "L2_READ_SNOOP",
+ "L2_READ_HIT",
+ "L2_CLEAN_MISS",
+ "L2_WRITE_LOOKUP",
+ "L2_SWRITE_LOOKUP",
+ "L2_WRITE_REPLAY",
+ "L2_WRITE_SNOOP",
+ "L2_WRITE_HIT",
+ "L2_EXT_READ_FULL",
+ "L2_EXT_READ_HALF",
+ "L2_EXT_WRITE_FULL",
+ "L2_EXT_WRITE_HALF",
+ "L2_EXT_READ",
+ "L2_EXT_READ_LINE",
+ "L2_EXT_WRITE",
+ "L2_EXT_WRITE_LINE",
+ "L2_EXT_WRITE_SMALL",
+ "L2_EXT_BARRIER",
+ "L2_EXT_AR_STALL",
+ "L2_EXT_R_BUF_FULL",
+ "L2_EXT_RD_BUF_FULL",
+ "L2_EXT_R_RAW",
+ "L2_EXT_W_STALL",
+ "L2_EXT_W_BUF_FULL",
+ "L2_EXT_R_W_HAZARD",
+ "L2_TAG_HAZARD",
+ "L2_SNOOP_FULL",
+ "L2_REPLAY_FULL"
+};
+
+#define NUMBER_OF_HARDWARE_COUNTERS (sizeof(hardware_counter_names) / sizeof(hardware_counter_names[0]))
+
+#define GET_HW_BLOCK(c) (((c) >> 6) & 0x3)
+#define GET_COUNTER_OFFSET(c) ((c) & 0x3f)
+
+/* Memory to dump hardware counters into */
+static void *kernel_dump_buffer;
+
+/* kbase context and device */
+static kbase_context *kbcontext = NULL;
+static struct kbase_device *kbdevice = NULL;
+
+extern struct kbase_device *kbase_find_device(int minor);
+static volatile bool kbase_device_busy = false;
+static unsigned int num_hardware_counters_enabled;
+
+/*
+ * gatorfs variables for counter enable state
+ */
+static mali_counter counters[NUMBER_OF_HARDWARE_COUNTERS];
+
+/* An array used to return the data we recorded
+ * as key,value pairs hence the *2
+ */
+static unsigned long counter_dump[NUMBER_OF_HARDWARE_COUNTERS * 2];
+
+static int start(void)
+{
+ kbase_uk_hwcnt_setup setup;
+ mali_error err;
+ int cnt;
+ u16 bitmask[] = {0, 0, 0, 0};
+
+ /* Setup HW counters */
+ num_hardware_counters_enabled = 0;
+
+ if(NUMBER_OF_HARDWARE_COUNTERS != 256)
+ {
+ pr_debug("Unexpected number of hardware counters defined: expecting 256, got %d\n", NUMBER_OF_HARDWARE_COUNTERS);
+ }
+
+ /* Calculate enable bitmasks based on counters_enabled array */
+ for (cnt = 0; cnt < NUMBER_OF_HARDWARE_COUNTERS; cnt++)
+ {
+ const mali_counter *counter = &counters[cnt];
+ if (counter->enabled)
+ {
+ int block = GET_HW_BLOCK(cnt);
+ int enable_bit = GET_COUNTER_OFFSET(cnt) / 4;
+ bitmask[block] |= (1 << enable_bit);
+ pr_debug("gator: Mali-T6xx: hardware counter %s selected [%d]\n", hardware_counter_names[cnt], cnt);
+ num_hardware_counters_enabled++;
+ }
+ }
+
+ /* Create a kbase context for HW counters */
+ if (num_hardware_counters_enabled > 0)
+ {
+ kbdevice = kbase_find_device(-1);
+
+ if (kbcontext)
+ return -1;
+
+ kbcontext = kbase_create_context(kbdevice);
+ if (!kbcontext)
+ {
+ pr_debug("gator: Mali-T6xx: error creating kbase context\n");
+ goto out;
+ }
+
+ /*
+ * The amount of memory needed to store the dump (bytes)
+ * DUMP_SIZE = number of core groups
+ * * number of blocks (always 8 for midgard)
+ * * number of counters per block (always 64 for midgard)
+ * * number of bytes per counter (always 4 in midgard)
+ * For a Mali-T6xx with a single core group = 1 * 8 * 64 * 4
+ */
+ kernel_dump_buffer = kbase_va_alloc(kbcontext, 2048);
+ if (!kernel_dump_buffer)
+ {
+ pr_debug("gator: Mali-T6xx: error trying to allocate va\n");
+ goto destroy_context;
+ }
+
+ setup.dump_buffer = (uintptr_t)kernel_dump_buffer;
+ setup.jm_bm = bitmask[JM_BLOCK];
+ setup.tiler_bm = bitmask[TILER_BLOCK];
+ setup.shader_bm = bitmask[SHADER_BLOCK];
+ setup.mmu_l2_bm = bitmask[MMU_BLOCK];
+ /* These counters do not exist on Mali-T60x */
+ setup.l3_cache_bm = 0;
+
+ /* Use kbase API to enable hardware counters and provide dump buffer */
+ err = kbase_instr_hwcnt_enable(kbcontext, &setup);
+ if (err != MALI_ERROR_NONE)
+ {
+ pr_debug("gator: Mali-T6xx: can't setup hardware counters\n");
+ goto free_buffer;
+ }
+ pr_debug("gator: Mali-T6xx: hardware counters enabled\n");
+ kbase_instr_hwcnt_clear(kbcontext);
+ pr_debug("gator: Mali-T6xx: hardware counters cleared \n");
+
+ kbase_device_busy = false;
+ }
+
+ return 0;
+
+ free_buffer:
+ kbase_va_free(kbcontext, kernel_dump_buffer);
+ destroy_context:
+ kbase_destroy_context(kbcontext);
+ out:
+ return -1;
+}
+
+static void stop(void) {
+ unsigned int cnt;
+ kbase_context *temp_kbcontext;
+
+ pr_debug("gator: Mali-T6xx: stop\n");
+
+ /* Set all counters as disabled */
+ for (cnt = 0; cnt < NUMBER_OF_HARDWARE_COUNTERS; cnt++) {
+ counters[cnt].enabled = 0;
+ }
+
+ /* Destroy the context for HW counters */
+ if (num_hardware_counters_enabled > 0 && kbcontext != NULL)
+ {
+ /*
+ * Set the global variable to NULL before destroying it, because
+ * other function will check this before using it.
+ */
+ temp_kbcontext = kbcontext;
+ kbcontext = NULL;
+
+ kbase_instr_hwcnt_disable(temp_kbcontext);
+ kbase_va_free(temp_kbcontext, kernel_dump_buffer);
+ kbase_destroy_context(temp_kbcontext);
+ pr_debug("gator: Mali-T6xx: hardware counters stopped\n");
+ }
+}
+
+static int read(int **buffer) {
+ int cnt;
+ int len = 0;
+ u32 value = 0;
+ mali_bool success;
+
+ if (smp_processor_id()!=0)
+ {
+ return 0;
+ }
+
+ /*
+ * Report the HW counters
+ * Only process hardware counters if at least one of the hardware counters is enabled.
+ */
+ if (num_hardware_counters_enabled > 0)
+ {
+ const unsigned int vithar_blocks[] = {
+ 0x700, /* VITHAR_JOB_MANAGER, Block 0 */
+ 0x400, /* VITHAR_TILER, Block 1 */
+ 0x000, /* VITHAR_SHADER_CORE, Block 2 */
+ 0x500 /* VITHAR_MEMORY_SYSTEM, Block 3 */
+ };
+
+ if (!kbcontext)
+ {
+ return -1;
+ }
+
+ // TODO: SYMBOL_GET (all kbase functions)
+ if (kbase_instr_hwcnt_dump_complete(kbcontext, &success) == MALI_TRUE)
+ {
+ kbase_device_busy = false;
+
+ if (success == MALI_TRUE)
+ {
+ for (cnt = 0; cnt < NUMBER_OF_HARDWARE_COUNTERS; cnt++)
+ {
+ const mali_counter *counter = &counters[cnt];
+ if (counter->enabled)
+ {
+ const int block = GET_HW_BLOCK(cnt);
+ const int counter_offset = GET_COUNTER_OFFSET(cnt);
+ const u32 *counter_block = (u32 *)((uintptr_t)kernel_dump_buffer + vithar_blocks[block]);
+ const u32 *counter_address = counter_block + counter_offset;
+
+ value = *counter_address;
+
+ if(block == SHADER_BLOCK){
+ /* (counter_address + 0x000) has already been accounted-for above. */
+ value += *(counter_address + 0x100);
+ value += *(counter_address + 0x200);
+ value += *(counter_address + 0x300);
+ }
+
+ counter_dump[len++] = counter->key;
+ counter_dump[len++] = value;
+ }
+ }
+ }
+ }
+
+ if (! kbase_device_busy)
+ {
+ kbase_device_busy = true;
+ kbase_instr_hwcnt_dump_irq(kbcontext);
+ }
+ }
+
+ /* Update the buffer */
+ if (buffer) {
+ *buffer = (int*) counter_dump;
+ }
+
+ return len;
+}
+
+static int create_files(struct super_block *sb, struct dentry *root)
+{
+ unsigned int event;
+ /*
+ * Create the filesystem for all events
+ */
+ int counter_index = 0;
+ const char* mali_name = gator_mali_get_mali_name();
+
+ for (event = 0; event < NUMBER_OF_HARDWARE_COUNTERS; event++)
+ {
+ if (gator_mali_create_file_system(mali_name, hardware_counter_names[counter_index], sb, root, &counters[event]) != 0)
+ return -1;
+ counter_index++;
+ }
+
+ return 0;
+}
+
+
+static struct gator_interface gator_events_mali_t6xx_interface = {
+ .create_files = create_files,
+ .start = start,
+ .stop = stop,
+ .read = read
+};
+
+int gator_events_mali_t6xx_hw_init(void)
+{
+ pr_debug("gator: Mali-T6xx: sw_counters init\n");
+
+ gator_mali_initialise_counters(counters, NUMBER_OF_HARDWARE_COUNTERS);
+
+ return gator_events_install(&gator_events_mali_t6xx_interface);
+}
+
+gator_events_init(gator_events_mali_t6xx_hw_init);
diff --git a/driver/gator_events_meminfo.c b/driver/gator_events_meminfo.c
index ad552ef..b962641 100644
--- a/driver/gator_events_meminfo.c
+++ b/driver/gator_events_meminfo.c
@@ -26,8 +26,9 @@ static unsigned int mem_event = 0;
static bool new_data_avail;
static void wq_sched_handler(struct work_struct *wsptr);
-
DECLARE_WORK(work, wq_sched_handler);
+static struct timer_list meminfo_wake_up_timer;
+static void meminfo_wake_up_handler(unsigned long unused_data);
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
GATOR_DEFINE_PROBE(mm_page_free_direct, TP_PROTO(struct page *page, unsigned int order)) {
@@ -107,6 +108,7 @@ static int gator_events_meminfo_start(void)
if (GATOR_REGISTER_TRACE(mm_page_alloc))
goto mm_page_alloc_exit;
+ setup_timer(&meminfo_wake_up_timer, meminfo_wake_up_handler, 0);
return 0;
mm_page_alloc_exit:
@@ -138,6 +140,8 @@ static void gator_events_meminfo_stop(void)
GATOR_UNREGISTER_TRACE(mm_page_free_batched);
#endif
GATOR_UNREGISTER_TRACE(mm_page_alloc);
+
+ del_timer_sync(&meminfo_wake_up_timer);
}
meminfo_global_enabled = 0;
@@ -146,7 +150,7 @@ static void gator_events_meminfo_stop(void)
}
}
-// Must be run in process context (work queue) as the kernel function si_meminfo() can sleep
+// Must be run in process context as the kernel function si_meminfo() can sleep
static void wq_sched_handler(struct work_struct *wsptr)
{
struct sysinfo info;
@@ -181,6 +185,12 @@ static void wq_sched_handler(struct work_struct *wsptr)
new_data_avail = true;
}
+static void meminfo_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
+ schedule_work(&work);
+}
+
static int gator_events_meminfo_read(long long **buffer)
{
static unsigned int last_mem_event = 0;
@@ -190,11 +200,7 @@ static int gator_events_meminfo_read(long long **buffer)
if (last_mem_event != mem_event) {
last_mem_event = mem_event;
- if (in_interrupt()) {
- schedule_work(&work);
- } else {
- wq_sched_handler(NULL);
- }
+ mod_timer(&meminfo_wake_up_timer, jiffies + 1);
}
if (!new_data_avail)
diff --git a/driver/gator_events_net.c b/driver/gator_events_net.c
index 9298905..11282b5 100644
--- a/driver/gator_events_net.c
+++ b/driver/gator_events_net.c
@@ -23,6 +23,9 @@ static int rx_total, tx_total;
static ulong netPrev[TOTALNET];
static int netGet[TOTALNET * 4];
+static struct timer_list net_wake_up_timer;
+
+// Must be run in process context as the kernel function dev_get_stats() can sleep
static void get_network_stats(struct work_struct *wsptr) {
int rx = 0, tx = 0;
struct net_device *dev;
@@ -42,6 +45,12 @@ static void get_network_stats(struct work_struct *wsptr) {
}
DECLARE_WORK(wq_get_stats, get_network_stats);
+static void net_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
+ schedule_work(&wq_get_stats);
+}
+
static void calculate_delta(int *rx, int *tx)
{
int rx_calc, tx_calc;
@@ -83,14 +92,16 @@ static int gator_events_net_create_files(struct super_block *sb, struct dentry *
static int gator_events_net_start(void)
{
- get_network_stats(NULL);
+ get_network_stats(0);
netPrev[NETRX] = rx_total;
netPrev[NETTX] = tx_total;
+ setup_timer(&net_wake_up_timer, net_wake_up_handler, 0);
return 0;
}
static void gator_events_net_stop(void)
{
+ del_timer_sync(&net_wake_up_timer);
netrx_enabled = 0;
nettx_enabled = 0;
}
@@ -106,11 +117,7 @@ static int gator_events_net_read(int **buffer)
if (!netrx_enabled && !nettx_enabled)
return 0;
- if (in_interrupt()){
- schedule_work(&wq_get_stats);
- } else {
- get_network_stats(NULL);
- }
+ mod_timer(&net_wake_up_timer, jiffies + 1);
calculate_delta(&rx_delta, &tx_delta);
diff --git a/driver/gator_events_perf_pmu.c b/driver/gator_events_perf_pmu.c
index da76a9c..9d78b46 100644
--- a/driver/gator_events_perf_pmu.c
+++ b/driver/gator_events_perf_pmu.c
@@ -32,6 +32,7 @@ static DEFINE_PER_CPU(int[CNTMAX], perfPrevDelta);
static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
static DEFINE_PER_CPU(struct perf_event *[CNTMAX], pevent);
static DEFINE_PER_CPU(struct perf_event_attr *[CNTMAX], pevent_attr);
+extern DEFINE_PER_CPU(struct perf_event *, pevent_ebs);
static void gator_events_perf_pmu_stop(void);
@@ -74,10 +75,15 @@ static void dummy_handler(struct perf_event *event, struct perf_sample_data *dat
static int gator_events_perf_pmu_online(int** buffer)
{
int cnt, len = 0, cpu = smp_processor_id();
+ struct perf_event * ev;
// read the counters and toss the invalid data, return zero instead
for (cnt = 0; cnt < pmnc_counters; cnt++) {
- struct perf_event * ev = per_cpu(pevent, cpu)[cnt];
+ if (pmnc_count[cnt] > 0) {
+ ev = per_cpu(pevent_ebs, cpu); // special case for EBS
+ } else {
+ ev = per_cpu(pevent, cpu)[cnt];
+ }
if (ev != NULL && ev->state == PERF_EVENT_STATE_ACTIVE) {
ev->pmu->read(ev);
per_cpu(perfPrev, cpu)[cnt] = per_cpu(perfCurr, cpu)[cnt] = local64_read(&ev->count);
@@ -101,6 +107,9 @@ static void gator_events_perf_pmu_online_dispatch(int cpu)
if (per_cpu(pevent, cpu)[cnt] != NULL || per_cpu(pevent_attr, cpu)[cnt] == 0)
continue;
+ if (pmnc_count[cnt] > 0)
+ continue; // skip the EBS counter
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
per_cpu(pevent, cpu)[cnt] = perf_event_create_kernel_counter(per_cpu(pevent_attr, cpu)[cnt], cpu, 0, dummy_handler);
#else
@@ -203,14 +212,19 @@ static int gator_events_perf_pmu_read(int **buffer)
{
int cnt, delta, len = 0;
int cpu = smp_processor_id();
+ struct perf_event * ev;
for (cnt = 0; cnt < pmnc_counters; cnt++) {
- struct perf_event * ev = per_cpu(pevent, cpu)[cnt];
+ if (pmnc_count[cnt] > 0) {
+ ev = per_cpu(pevent_ebs, cpu); // special case for EBS
+ } else {
+ ev = per_cpu(pevent, cpu)[cnt];
+ }
if (ev != NULL && ev->state == PERF_EVENT_STATE_ACTIVE) {
ev->pmu->read(ev);
per_cpu(perfCurr, cpu)[cnt] = local64_read(&ev->count);
delta = per_cpu(perfCurr, cpu)[cnt] - per_cpu(perfPrev, cpu)[cnt];
- if (delta != per_cpu(perfPrevDelta, cpu)[cnt]) {
+ if (delta != 0 || delta != per_cpu(perfPrevDelta, cpu)[cnt]) {
per_cpu(perfPrevDelta, cpu)[cnt] = delta;
per_cpu(perfPrev, cpu)[cnt] = per_cpu(perfCurr, cpu)[cnt];
per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
diff --git a/driver/gator_fs.c b/driver/gator_fs.c
index 39adfbe..81b0d5b 100644
--- a/driver/gator_fs.c
+++ b/driver/gator_fs.c
@@ -251,7 +251,6 @@ static int gatorfs_fill_super(struct super_block *sb, void *data, int silent)
gator_op_create_files(sb, root_dentry);
- // FIXME: verify kill_litter_super removes our dentries
return 0;
}
diff --git a/driver/gator_main.c b/driver/gator_main.c
index 7d48812..db728ad 100644
--- a/driver/gator_main.c
+++ b/driver/gator_main.c
@@ -7,7 +7,7 @@
*
*/
-static unsigned long gator_protocol_version = 9;
+static unsigned long gator_protocol_version = 10;
#include <linux/slab.h>
#include <linux/cpu.h>
@@ -108,8 +108,12 @@ static DEFINE_MUTEX(start_mutex);
static DEFINE_MUTEX(gator_buffer_mutex);
bool event_based_sampling;
+#if defined(__arm__) && (GATOR_PERF_PMU_SUPPORT)
+DEFINE_PER_CPU(struct perf_event *, pevent_ebs);
+#endif
static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait);
+static struct timer_list gator_buffer_wake_up_timer;
static LIST_HEAD(gator_events);
/******************************************************************************
@@ -163,6 +167,11 @@ u32 gator_cpuid(void)
}
#endif
+static void gator_buffer_wake_up(unsigned long data)
+{
+ wake_up(&gator_buffer_wait);
+}
+
/******************************************************************************
* Commit interface
******************************************************************************/
@@ -283,7 +292,9 @@ static void gator_commit_buffer(int cpu, int buftype)
per_cpu(gator_buffer_commit, cpu)[buftype] = per_cpu(gator_buffer_write, cpu)[buftype];
gator_buffer_header(cpu, buftype);
- wake_up(&gator_buffer_wait);
+
+ // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
+ mod_timer(&gator_buffer_wake_up_timer, jiffies + 1);
}
static void buffer_check(int cpu, int buftype)
@@ -682,11 +693,6 @@ static void gator_stop(void)
{
struct gator_interface *gi;
- // stop all events
- list_for_each_entry(gi, &gator_events, list)
- if (gi->stop)
- gi->stop();
-
gator_annotate_stop();
gator_trace_sched_stop();
gator_trace_power_stop();
@@ -696,6 +702,11 @@ static void gator_stop(void)
// stop all interrupt callback reads before tearing down other interfaces
gator_notifier_stop(); // should be called before gator_timer_stop to avoid re-enabling the hrtimer after it has been offlined
gator_timer_stop();
+
+ // stop all events
+ list_for_each_entry(gi, &gator_events, list)
+ if (gi->stop)
+ gi->stop();
}
/******************************************************************************
@@ -1069,11 +1080,14 @@ static int __init gator_module_init(void)
return -1;
}
+ setup_timer(&gator_buffer_wake_up_timer, gator_buffer_wake_up, 0);
+
return 0;
}
static void __exit gator_module_exit(void)
{
+ del_timer_sync(&gator_buffer_wake_up_timer);
tracepoint_synchronize_unregister();
gatorfs_unregister();
}
diff --git a/driver/gator_trace_gpu.c b/driver/gator_trace_gpu.c
index 921932c..d053987 100644
--- a/driver/gator_trace_gpu.c
+++ b/driver/gator_trace_gpu.c
@@ -18,11 +18,19 @@
#endif
#include "gator_trace_gpu.h"
-#define ACTIVITY_START 1
-#define ACTIVITY_STOP 2
+/*
+ * Taken from MALI_PROFILING_EVENT_TYPE_* items in Mali DDK.
+ */
+#define EVENT_TYPE_SINGLE 0
+#define EVENT_TYPE_START 1
+#define EVENT_TYPE_STOP 2
+#define EVENT_TYPE_SUSPEND 3
+#define EVENT_TYPE_RESUME 4
+
/* Note whether tracepoints have been registered */
-static int mali_trace_registered;
+static int mali_timeline_trace_registered;
+static int mali_job_slots_trace_registered;
static int gpu_trace_registered;
#define GPU_START 1
@@ -32,42 +40,107 @@ static int gpu_trace_registered;
#define GPU_UNIT_FP 2
#define GPU_UNIT_CL 3
-#ifdef MALI_SUPPORT
+#define MALI_400 (0x0b07)
+#define MALI_T6xx (0x0056)
+
+#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx)
+#include "gator_events_mali_400.h"
-enum components {
- COMPONENT_VP0 = 1,
- COMPONENT_FP0 = 5,
- COMPONENT_FP1,
- COMPONENT_FP2,
- COMPONENT_FP3,
- COMPONENT_FP4,
- COMPONENT_FP5,
- COMPONENT_FP6,
- COMPONENT_FP7,
+/*
+ * Taken from MALI_PROFILING_EVENT_CHANNEL_* in Mali DDK.
+ */
+enum {
+ EVENT_CHANNEL_SOFTWARE = 0,
+ EVENT_CHANNEL_VP0 = 1,
+ EVENT_CHANNEL_FP0 = 5,
+ EVENT_CHANNEL_FP1,
+ EVENT_CHANNEL_FP2,
+ EVENT_CHANNEL_FP3,
+ EVENT_CHANNEL_FP4,
+ EVENT_CHANNEL_FP5,
+ EVENT_CHANNEL_FP6,
+ EVENT_CHANNEL_FP7,
+ EVENT_CHANNEL_GPU = 21
+};
+
+/**
+ * These events are applicable when the type MALI_PROFILING_EVENT_TYPE_SINGLE is used from the GPU channel
+ */
+enum {
+ EVENT_REASON_SINGLE_GPU_NONE = 0,
+ EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE = 1,
};
+
GATOR_DEFINE_PROBE(mali_timeline_event, TP_PROTO(unsigned int event_id, unsigned int d0, unsigned int d1, unsigned int d2, unsigned int d3, unsigned int d4))
{
unsigned int component, state;
- int tgid = 0, pid = 0;
// do as much work as possible before disabling interrupts
component = (event_id >> 16) & 0xFF; // component is an 8-bit field
state = (event_id >> 24) & 0xF; // state is a 4-bit field
- if ((component == COMPONENT_VP0) || (component >= COMPONENT_FP0 && component <= COMPONENT_FP7)) {
- if (state == ACTIVITY_START || state == ACTIVITY_STOP) {
- unsigned int type = (state == ACTIVITY_START) ? GPU_START : GPU_STOP;
- unsigned int unit = (component < COMPONENT_FP0) ? GPU_UNIT_VP : GPU_UNIT_FP;
- unsigned int core = (component < COMPONENT_FP0) ? component - COMPONENT_VP0 : component - COMPONENT_FP0;
- if (state == ACTIVITY_START) {
- tgid = d0;
- pid = d1;
+ switch (state) {
+ case EVENT_TYPE_START:
+ if (component == EVENT_CHANNEL_VP0) {
+ /* tgid = d0; pid = d1; */
+ marshal_sched_gpu(GPU_START, GPU_UNIT_VP, 0, d0, d1);
+ } else if (component >= EVENT_CHANNEL_FP0 && component <= EVENT_CHANNEL_FP7) {
+ /* tgid = d0; pid = d1; */
+ marshal_sched_gpu(GPU_START, GPU_UNIT_FP, component - EVENT_CHANNEL_FP0, d0, d1);
+ }
+ break;
+
+ case EVENT_TYPE_STOP:
+ if (component == EVENT_CHANNEL_VP0) {
+ marshal_sched_gpu(GPU_STOP, GPU_UNIT_VP, 0, 0, 0);
+ } else if (component >= EVENT_CHANNEL_FP0 && component <= EVENT_CHANNEL_FP7) {
+ marshal_sched_gpu(GPU_STOP, GPU_UNIT_FP, component - EVENT_CHANNEL_FP0, 0, 0);
+ }
+ break;
+
+ case EVENT_TYPE_SINGLE:
+ if (component == EVENT_CHANNEL_GPU) {
+ unsigned int reason = (event_id & 0xffff);
+
+ if(reason == EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE) {
+ gator_events_mali_log_dvfs_event(d0, d1);
}
+ }
+ break;
- marshal_sched_gpu(type, unit, core, tgid, pid);
- }
- }
+ default:
+ break;
+ }
+}
+#endif
+
+#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_T6xx)
+GATOR_DEFINE_PROBE(mali_job_slots_event, TP_PROTO(unsigned int event_id, unsigned int tgid, unsigned int pid))
+{
+ unsigned int component, state, type, unit = 0;
+
+ component = (event_id >> 16) & 0xFF; // component is an 8-bit field
+ state = (event_id >> 24) & 0xF; // state is a 4-bit field
+ type = (state == EVENT_TYPE_START) ? GPU_START : GPU_STOP;
+
+ switch (component)
+ {
+ case 0:
+ unit = GPU_UNIT_FP;
+ break;
+ case 1:
+ unit = GPU_UNIT_VP;
+ break;
+ case 2:
+ unit = GPU_UNIT_CL;
+ break;
+ }
+
+ if (unit != 0)
+ {
+ marshal_sched_gpu(type, unit, 0, tgid, (pid != 0 ? pid : tgid));
+ }
}
#endif
@@ -88,15 +161,21 @@ int gator_trace_gpu_start(void)
* Absence of gpu trace points is not an error
*/
- gpu_trace_registered = mali_trace_registered = 0;
+ gpu_trace_registered = mali_timeline_trace_registered = mali_job_slots_trace_registered = 0;
-#ifdef MALI_SUPPORT
+#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx)
if (!GATOR_REGISTER_TRACE(mali_timeline_event)) {
- mali_trace_registered = 1;
+ mali_timeline_trace_registered = 1;
}
#endif
- if (!mali_trace_registered) {
+#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_T6xx)
+ if (!GATOR_REGISTER_TRACE(mali_job_slots_event)) {
+ mali_job_slots_trace_registered = 1;
+ }
+#endif
+
+ if (!mali_timeline_trace_registered) {
if (GATOR_REGISTER_TRACE(gpu_activity_start)) {
return 0;
}
@@ -112,15 +191,22 @@ int gator_trace_gpu_start(void)
void gator_trace_gpu_stop(void)
{
-#ifdef MALI_SUPPORT
- if (mali_trace_registered) {
+#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx)
+ if (mali_timeline_trace_registered) {
GATOR_UNREGISTER_TRACE(mali_timeline_event);
}
#endif
+
+#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_T6xx)
+ if (mali_job_slots_trace_registered) {
+ GATOR_UNREGISTER_TRACE(mali_job_slots_event);
+ }
+#endif
+
if (gpu_trace_registered) {
GATOR_UNREGISTER_TRACE(gpu_activity_stop);
GATOR_UNREGISTER_TRACE(gpu_activity_start);
}
- gpu_trace_registered = mali_trace_registered = 0;
+ gpu_trace_registered = mali_timeline_trace_registered = mali_job_slots_trace_registered = 0;
}
diff --git a/driver/mali_t6xx.mk b/driver/mali_t6xx.mk
new file mode 100644
index 0000000..2e51670
--- /dev/null
+++ b/driver/mali_t6xx.mk
@@ -0,0 +1,24 @@
+# Defines for Mali-T6xx driver
+EXTRA_CFLAGS += -DMALI_USE_UMP=1 \
+ -DMALI_LICENSE_IS_GPL=1 \
+ -DMALI_BASE_TRACK_MEMLEAK=0 \
+ -DMALI_DEBUG=0 \
+ -DMALI_ERROR_INJECT_ON=0 \
+ -DMALI_CUSTOMER_RELEASE=1 \
+ -DMALI_UNIT_TEST=0 \
+ -DMALI_BACKEND_KERNEL=1 \
+ -DMALI_NO_MALI=0
+
+KBASE_DIR = $(DDK_DIR)/kernel/drivers/gpu/arm/t6xx/kbase
+OSK_DIR = $(DDK_DIR)/kernel/drivers/gpu/arm/t6xx/kbase/osk
+UMP_DIR = $(DDK_DIR)/kernel/drivers/gpu/arm/ump
+
+# Include directories in the DDK
+EXTRA_CFLAGS += -I$(DDK_DIR) \
+ -I$(KBASE_DIR)/.. \
+ -I$(OSK_DIR)/.. \
+ -I$(UMP_DIR)/.. \
+ -I$(KBASE_DIR)/osk/src/linux/include \
+ -I$(KBASE_DIR)/platform_dummy \
+ -I$(KBASE_DIR)/src
+