gator: Version 5.17

Signed-off-by: Jon Medhurst <tixy@linaro.org>
diff --git a/drivers/gator/Makefile b/drivers/gator/Makefile
index 0d4ca68..3dc9d05 100644
--- a/drivers/gator/Makefile
+++ b/drivers/gator/Makefile
@@ -3,7 +3,8 @@
 # Uncomment the following line to enable kernel stack unwinding within gator, or update gator_backtrace.c
 # EXTRA_CFLAGS +=	-DGATOR_KERNEL_STACK_UNWINDING
 
-obj-m := gator.o
+CONFIG_GATOR ?= m
+obj-$(CONFIG_GATOR) := gator.o
 
 gator-y :=	gator_main.o \
 		gator_events_irq.o \
@@ -11,23 +12,40 @@
 		gator_events_net.o \
 		gator_events_block.o \
 		gator_events_meminfo.o \
-		gator_events_perf_pmu.o
+		gator_events_perf_pmu.o \
+		gator_events_mmapped.o \
 
-gator-y +=	gator_events_mmaped.o
-
+# Convert the old GATOR_WITH_MALI_SUPPORT to the new kernel flags
 ifneq ($(GATOR_WITH_MALI_SUPPORT),)
-ifeq ($(GATOR_WITH_MALI_SUPPORT),MALI_T6xx)
-gator-y +=	gator_events_mali_t6xx.o \
+  CONFIG_GATOR_WITH_MALI_SUPPORT := y
+  ifeq ($(GATOR_WITH_MALI_SUPPORT),MALI_T6xx)
+    CONFIG_GATOR_MALI_4XXMP := n
+    CONFIG_GATOR_MALI_T6XX := y
+  else
+    CONFIG_GATOR_MALI_4XXMP := y
+    CONFIG_GATOR_MALI_T6XX := n
+  endif
+  EXTRA_CFLAGS += -DMALI_SUPPORT=$(GATOR_WITH_MALI_SUPPORT)
+  ifneq ($(GATOR_MALI_INTERFACE_STYLE),)
+    EXTRA_CFLAGS += -DGATOR_MALI_INTERFACE_STYLE=$(GATOR_MALI_INTERFACE_STYLE)
+  endif
+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 $(M)/mali_t6xx.mk
-else
-gator-y +=	gator_events_mali_4xx.o
-endif
-gator-y +=	gator_events_mali_common.o
-EXTRA_CFLAGS +=	-DMALI_SUPPORT=$(GATOR_WITH_MALI_SUPPORT)
-ifneq ($(GATOR_MALI_INTERFACE_STYLE),)
-EXTRA_CFLAGS += -DGATOR_MALI_INTERFACE_STYLE=$(GATOR_MALI_INTERFACE_STYLE)
-endif
+    include $(src)/mali_t6xx.mk
+  else
+    gator-y +=	gator_events_mali_4xx.o
+  endif
+  gator-y +=	gator_events_mali_common.o
+
+  ifneq ($(CONFIG_GATOR_MALI_PATH),)
+    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
 endif
 
 # GATOR_TEST controls whether to include (=1) or exclude (=0) test code. 
@@ -42,17 +60,6 @@
 
 gator-$(CONFIG_ARM64) +=	gator_events_ccn-504.o
 
-$(obj)/gator_main.o: gator_events.h
-
-clean-files := gator_events.h
-
-       chk_events.h = :
- quiet_chk_events.h = echo '  CHK     $@'
-silent_chk_events.h = :
-gator_events.h: FORCE
-	@$($(quiet)chk_events.h)
-	$(Q)cd $(obj) ; $(CONFIG_SHELL) $(obj)/gator_events.sh $@
-
 else
 
 all:
@@ -63,7 +70,7 @@
 	$(error)
 
 clean:
-	rm -f *.o .*.cmd gator_events.h modules.order Module.symvers gator.ko gator.mod.c
+	rm -f *.o .*.cmd modules.order Module.symvers gator.ko gator.mod.c
 	rm -rf .tmp_versions
 
 endif
diff --git a/drivers/gator/gator.h b/drivers/gator/gator.h
index 2e122da..d8981ed 100644
--- a/drivers/gator/gator.h
+++ b/drivers/gator/gator.h
@@ -112,14 +112,10 @@
 	void (*offline_dispatch)(int cpu, bool migrate);	// called in process context but may not be running on core 'cpu'
 	int (*read)(int **buffer);
 	int (*read64)(long long **buffer);
+	int (*read_proc)(long long **buffer, struct task_struct *);
 	struct list_head list;
 };
 
-// gator_events_init is used as a search term in gator_events.sh
-#define gator_events_init(initfn) \
-	static inline int __gator_events_init_test(void) \
-	{ return initfn(); }
-
 int gator_events_install(struct gator_interface *interface);
 int gator_events_get_key(void);
 u32 gator_cpuid(void);
diff --git a/drivers/gator/gator_annotate_kernel.c b/drivers/gator/gator_annotate_kernel.c
index 4715f64..a406e48 100644
--- a/drivers/gator/gator_annotate_kernel.c
+++ b/drivers/gator/gator_annotate_kernel.c
@@ -29,11 +29,27 @@
 	}
 }
 
+static void marshal_u16(char *buf, u16 val) {
+	buf[0] = val & 0xff;
+	buf[1] = (val >> 8) & 0xff;
+}
+
+static void marshal_u32(char *buf, u32 val) {
+	buf[0] = val & 0xff;
+	buf[1] = (val >> 8) & 0xff;
+	buf[2] = (val >> 16) & 0xff;
+	buf[3] = (val >> 24) & 0xff;
+}
+
 void gator_annotate_channel(int channel, const char *str)
 {
-	int str_size = strlen(str) & 0xffff;
-	long long header = ESCAPE_CODE | (STRING_ANNOTATION << 8) | (channel << 16) | ((long long)str_size << 48);
-	kannotate_write((char *)&header, sizeof(header));
+	const u16 str_size = strlen(str) & 0xffff;
+	char header[8];
+	header[0] = ESCAPE_CODE;
+	header[1] = STRING_ANNOTATION;
+	marshal_u32(header + 2, channel);
+	marshal_u16(header + 6, str_size);
+	kannotate_write(header, sizeof(header));
 	kannotate_write(str, str_size);
 }
 
@@ -48,14 +64,14 @@
 
 void gator_annotate_channel_color(int channel, int color, const char *str)
 {
-	int str_size = (strlen(str) + 4) & 0xffff;
+	const u16 str_size = (strlen(str) + 4) & 0xffff;
 	char header[12];
 	header[0] = ESCAPE_CODE;
 	header[1] = STRING_ANNOTATION;
-	*(u32 *)(&header[2]) = channel;
-	*(u16 *)(&header[6]) = str_size;
-	*(u32 *)(&header[8]) = color;
-	kannotate_write((char *)&header, sizeof(header));
+	marshal_u32(header + 2, channel);
+	marshal_u16(header + 6, str_size);
+	marshal_u32(header + 8, color);
+	kannotate_write(header, sizeof(header));
 	kannotate_write(str, str_size - 4);
 }
 
@@ -70,8 +86,12 @@
 
 void gator_annotate_channel_end(int channel)
 {
-	long long header = ESCAPE_CODE | (STRING_ANNOTATION << 8) | (channel << 16);
-	kannotate_write((char *)&header, sizeof(header));
+	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);
@@ -85,14 +105,14 @@
 
 void gator_annotate_name_channel(int channel, int group, const char* str)
 {
-	int str_size = strlen(str) & 0xffff;
+	const u16 str_size = strlen(str) & 0xffff;
 	char header[12];
 	header[0] = ESCAPE_CODE;
 	header[1] = NAME_CHANNEL_ANNOTATION;
-	*(u32 *)(&header[2]) = channel;
-	*(u32 *)(&header[6]) = group;
-	*(u16 *)(&header[10]) = str_size;
-	kannotate_write((char *)&header, sizeof(header));
+	marshal_u32(header + 2, channel);
+	marshal_u32(header + 6, group);
+	marshal_u16(header + 10, str_size);
+	kannotate_write(header, sizeof(header));
 	kannotate_write(str, str_size);
 }
 
@@ -100,9 +120,13 @@
 
 void gator_annotate_name_group(int group, const char* str)
 {
-	int str_size = strlen(str) & 0xffff;
-	long long header = ESCAPE_CODE | (NAME_GROUP_ANNOTATION << 8) | (group << 16) | ((long long)str_size << 48);
-	kannotate_write((char *)&header, sizeof(header));
+	const u16 str_size = strlen(str) & 0xffff;
+	char header[8];
+	header[0] = ESCAPE_CODE;
+	header[1] = NAME_GROUP_ANNOTATION;
+	marshal_u32(header + 2, group);
+	marshal_u16(header + 6, str_size);
+	kannotate_write(header, sizeof(header));
 	kannotate_write(str, str_size);
 }
 
@@ -110,11 +134,16 @@
 
 void gator_annotate_visual(const char *data, unsigned int length, const char *str)
 {
-	int str_size = strlen(str) & 0xffff;
-	int visual_annotation = ESCAPE_CODE | (VISUAL_ANNOTATION << 8) | (str_size << 16);
-	kannotate_write((char *)&visual_annotation, sizeof(visual_annotation));
+	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);
+	marshal_u32(header_length, length);
+	kannotate_write(header, sizeof(header));
 	kannotate_write(str, str_size);
-	kannotate_write((char *)&length, sizeof(length));
+	kannotate_write(header_length, sizeof(header_length));
 	kannotate_write(data, length);
 }
 
@@ -122,17 +151,23 @@
 
 void gator_annotate_marker(void)
 {
-	int header = ESCAPE_CODE | (MARKER_ANNOTATION << 8);
-	kannotate_write((char *)&header, sizeof(header));
+	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)
 {
-	int str_size = strlen(str) & 0xffff;
-	int header = ESCAPE_CODE | (MARKER_ANNOTATION << 8) | (str_size << 16);
-	kannotate_write((char *)&header, sizeof(header));
+	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);
 }
 
@@ -140,17 +175,25 @@
 
 void gator_annotate_marker_color(int color)
 {
-	long long header = (ESCAPE_CODE | (MARKER_ANNOTATION << 8) | 0x00040000 | ((long long)color << 32));
-	kannotate_write((char *)&header, sizeof(header));
+	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)
 {
-	int str_size = (strlen(str) + 4) & 0xffff;
-	long long header = ESCAPE_CODE | (MARKER_ANNOTATION << 8) | (str_size << 16) | ((long long)color << 32);
-	kannotate_write((char *)&header, sizeof(header));
+	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);
+	marshal_u32(header + 4, color);
+	kannotate_write(header, sizeof(header));
 	kannotate_write(str, str_size - 4);
 }
 
diff --git a/drivers/gator/gator_backtrace.c b/drivers/gator/gator_backtrace.c
index 0670d6c..ffacb49 100644
--- a/drivers/gator/gator_backtrace.c
+++ b/drivers/gator/gator_backtrace.c
@@ -132,13 +132,21 @@
 
 // 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
+MODULE_PARM_DESC(kernel_stack_unwinding, "Allow kernel stack unwinding.");
+bool kernel_stack_unwinding = 0;
+module_param(kernel_stack_unwinding, bool, 0644);
+#endif
+
 static void kernel_backtrace(int cpu, struct pt_regs *const regs)
 {
 #if defined(__arm__) || defined(__aarch64__)
 #ifdef GATOR_KERNEL_STACK_UNWINDING
 	int depth = gator_backtrace_depth;
 #else
-	int depth = 1;
+	int depth = (kernel_stack_unwinding ? gator_backtrace_depth : 1);
 #endif
 	struct stackframe frame;
 	if (depth == 0)
diff --git a/drivers/gator/gator_cookies.c b/drivers/gator/gator_cookies.c
index 5f98a1c..91adfdd 100644
--- a/drivers/gator/gator_cookies.c
+++ b/drivers/gator/gator_cookies.c
@@ -8,7 +8,8 @@
  */
 
 #define COOKIEMAP_ENTRIES	1024	/* must be power of 2 */
-#define TRANSLATE_SIZE		256
+#define TRANSLATE_BUFFER_SIZE 512  // must be a power of 2 - 512/4 = 128 entries
+#define TRANSLATE_TEXT_SIZE		256
 #define MAX_COLLISIONS		2
 
 static uint32_t *gator_crc32_table;
@@ -22,7 +23,7 @@
 static DEFINE_PER_CPU(int, translate_buffer_write);
 static DEFINE_PER_CPU(void **, translate_buffer);
 
-static inline uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq);
+static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq);
 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;
@@ -107,11 +108,13 @@
 	values[0] = value;
 }
 
+#ifndef CONFIG_PREEMPT_RT_FULL
 static void translate_buffer_write_ptr(int cpu, void *x)
 {
 	per_cpu(translate_buffer, cpu)[per_cpu(translate_buffer_write, cpu)++] = x;
 	per_cpu(translate_buffer_write, cpu) &= translate_buffer_mask;
 }
+#endif
 
 static void *translate_buffer_read_ptr(int cpu)
 {
@@ -124,7 +127,7 @@
 {
 	struct task_struct *task;
 	char *text;
-	int cpu = get_physical_cpu();
+	int cpu = get_physical_cpu(), cookie;
 	unsigned int commit;
 
 	mutex_lock(&start_mutex);
@@ -134,7 +137,8 @@
 		while (per_cpu(translate_buffer_read, cpu) != commit) {
 			task = (struct task_struct *)translate_buffer_read_ptr(cpu);
 			text = (char *)translate_buffer_read_ptr(cpu);
-			get_cookie(cpu, task, text, true);
+			cookie = get_cookie(cpu, task, text, true);
+			marshal_link(cookie, task->tgid, task->pid);
 		}
 	}
 
@@ -156,15 +160,16 @@
 	struct mm_struct *mm;
 	struct page *page = NULL;
 	struct vm_area_struct *page_vma;
-	int bytes, offset, retval = 0, ptr;
+	int bytes, offset, retval = 0;
 	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
 	if (!from_wq) {
 		// Check if already in buffer
-		ptr = per_cpu(translate_buffer_read, cpu);
+		int ptr = per_cpu(translate_buffer_read, cpu);
 		while (ptr != per_cpu(translate_buffer_write, cpu)) {
 			if (per_cpu(translate_buffer, cpu)[ptr] == (void *)task)
 				goto out;
@@ -174,9 +179,11 @@
 		translate_buffer_write_ptr(cpu, (void *)task);
 		translate_buffer_write_ptr(cpu, (void *)*text);
 
+		// Not safe to call in RT-Preempt full in schedule switch context
 		mod_timer(&app_process_wake_up_timer, jiffies + 1);
 		goto out;
 	}
+#endif
 
 	mm = get_task_mm(task);
 	if (!mm)
@@ -186,8 +193,8 @@
 	addr = mm->arg_start;
 	len = mm->arg_end - mm->arg_start;
 
-	if (len > TRANSLATE_SIZE)
-		len = TRANSLATE_SIZE;
+	if (len > TRANSLATE_TEXT_SIZE)
+		len = TRANSLATE_TEXT_SIZE;
 
 	down_read(&mm->mmap_sem);
 	while (len) {
@@ -225,7 +232,7 @@
 	return retval;
 }
 
-static inline uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq)
+static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq)
 {
 	unsigned long flags, cookie;
 	uint64_t key;
@@ -312,8 +319,7 @@
 	uint32_t crc, poly;
 	int i, j, cpu, size, err = 0;
 
-	int translate_buffer_size = 512;	// must be a power of 2
-	translate_buffer_mask = translate_buffer_size / sizeof(per_cpu(translate_buffer, 0)[0]) - 1;
+	translate_buffer_mask = TRANSLATE_BUFFER_SIZE / sizeof(per_cpu(translate_buffer, 0)[0]) - 1;
 
 	for_each_present_cpu(cpu) {
 		per_cpu(cookie_next_key, cpu) = nr_cpu_ids + cpu;
@@ -334,7 +340,7 @@
 		}
 		memset(per_cpu(cookie_values, cpu), 0, size);
 
-		per_cpu(translate_buffer, cpu) = (void **)kmalloc(translate_buffer_size, GFP_KERNEL);
+		per_cpu(translate_buffer, cpu) = (void **)kmalloc(TRANSLATE_BUFFER_SIZE, GFP_KERNEL);
 		if (!per_cpu(translate_buffer, cpu)) {
 			err = -ENOMEM;
 			goto cookie_setup_error;
@@ -343,7 +349,7 @@
 		per_cpu(translate_buffer_write, cpu) = 0;
 		per_cpu(translate_buffer_read, cpu) = 0;
 
-		per_cpu(translate_text, cpu) = (char *)kmalloc(TRANSLATE_SIZE, GFP_KERNEL);
+		per_cpu(translate_text, cpu) = (char *)kmalloc(TRANSLATE_TEXT_SIZE, GFP_KERNEL);
 		if (!per_cpu(translate_text, cpu)) {
 			err = -ENOMEM;
 			goto cookie_setup_error;
@@ -353,6 +359,10 @@
 	// build CRC32 table
 	poly = 0x04c11db7;
 	gator_crc32_table = (uint32_t *)kmalloc(256 * sizeof(uint32_t), GFP_KERNEL);
+	if (!gator_crc32_table) {
+		err = -ENOMEM;
+		goto cookie_setup_error;
+	}
 	for (i = 0; i < 256; i++) {
 		crc = i;
 		for (j = 8; j > 0; j--) {
diff --git a/drivers/gator/gator_events.sh b/drivers/gator/gator_events.sh
deleted file mode 100755
index 5467dd6..0000000
--- a/drivers/gator/gator_events.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/sh
-
-EVENTS=`grep gator_events_init *.c | sed 's/.\+gator_events_init(\(.\+\)).\+/\1/'`
-
-(
-	echo /\* This file is auto generated \*/
-	echo
-	for EVENT in $EVENTS; do
-		echo __weak int $EVENT\(void\)\;
-	done
-	echo
-	echo static int \(*gator_events_list[]\)\(void\) = {
-	for EVENT in $EVENTS; do
-		echo \	$EVENT,
-	done
-	echo }\;
-) > $1.tmp
-
-cmp -s $1 $1.tmp && rm $1.tmp || mv $1.tmp $1
diff --git a/drivers/gator/gator_events_armv6.c b/drivers/gator/gator_events_armv6.c
index 4f1bca6..dd79740 100644
--- a/drivers/gator/gator_events_armv6.c
+++ b/drivers/gator/gator_events_armv6.c
@@ -234,11 +234,4 @@
 	return gator_events_install(&gator_events_armv6_interface);
 }
 
-gator_events_init(gator_events_armv6_init);
-
-#else
-int gator_events_armv6_init(void)
-{
-	return -1;
-}
 #endif
diff --git a/drivers/gator/gator_events_armv7.c b/drivers/gator/gator_events_armv7.c
index 58f2956..30881c8 100644
--- a/drivers/gator/gator_events_armv7.c
+++ b/drivers/gator/gator_events_armv7.c
@@ -309,11 +309,4 @@
 	return gator_events_install(&gator_events_armv7_interface);
 }
 
-gator_events_init(gator_events_armv7_init);
-
-#else
-int gator_events_armv7_init(void)
-{
-	return -1;
-}
 #endif
diff --git a/drivers/gator/gator_events_block.c b/drivers/gator/gator_events_block.c
index 56c6a67..691ef25 100644
--- a/drivers/gator/gator_events_block.c
+++ b/drivers/gator/gator_events_block.c
@@ -151,5 +151,3 @@
 
 	return gator_events_install(&gator_events_block_interface);
 }
-
-gator_events_init(gator_events_block_init);
diff --git a/drivers/gator/gator_events_ccn-504.c b/drivers/gator/gator_events_ccn-504.c
index b91a9a1..b892319 100644
--- a/drivers/gator/gator_events_ccn-504.c
+++ b/drivers/gator/gator_events_ccn-504.c
@@ -6,23 +6,16 @@
  * published by the Free Software Foundation.
  */
 
-/*******************************************************************************
- * WARNING: This code is an experimental implementation of the CCN-504 hardware
- * counters which has not been tested on the hardware. Commented debug
- * statements are present and can be uncommented for diagnostic purposes.
- ******************************************************************************/
-
 #include <linux/io.h>
 #include <linux/module.h>
 
 #include "gator.h"
 
-#define PERIPHBASE 0x2E000000
-
 #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
@@ -34,27 +27,86 @@
 
 // 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 (4 + 1)
+#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 unsigned long ccn504_addr = 0;
-module_param(ccn504_addr, ulong, 0444);
+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)
 {
@@ -96,7 +148,6 @@
 
 	dt_config = readl(gator_events_ccn504_base + (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG);
 	dt_config |= (value + event_num) << (4*event_num);
-	//printk(KERN_ERR "%s(%s:%i) writel %x %x\n", __FUNCTION__, __FILE__, __LINE__, dt_config, (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG);
 	writel(dt_config, gator_events_ccn504_base + (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG);
 }
 
@@ -104,6 +155,20 @@
 {
 	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?
@@ -112,9 +177,22 @@
 	// [4:1] cntcfg = 0
 	// Enable PMU features
 	// [0] pmu_en = 1
-	//printk(KERN_ERR "%s(%s:%i) writel %x %x\n", __FUNCTION__, __FILE__, __LINE__, 0x1, REGION_DEBUG*REGION_SIZE + PMCR);
 	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
@@ -134,15 +212,14 @@
 		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]);
-		//printk(KERN_ERR "%s(%s:%i) pmu_event_id: %x node_type: %x region: %x\n", __FUNCTION__, __FILE__, __LINE__, pmu_event_id, node_type, region);
 
 		// 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 "%s(%s:%i) oly_id is %x expected %x\n", __FUNCTION__, __FILE__, __LINE__, 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;
 		}
 
@@ -160,7 +237,6 @@
 			gator_events_ccn504_set_dt_config(node_id/2, i, (node_id & 1) == 0 ? 0x8 : 0xC);
 			break;
 		}
-		//printk(KERN_ERR "%s(%s:%i) writel %x %x\n", __FUNCTION__, __FILE__, __LINE__, pmu_event_sel, region*REGION_SIZE + PMU_EVENT_SEL);
 		writel(pmu_event_sel, gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL);
 	}
 
@@ -171,21 +247,25 @@
 {
 	int i;
 
+	if (!gator_events_ccn504_global_enabled) {
+		return;
+	}
+
 	// cycle counter does not need to be disabled
 	for (i = 0; i < CCNT; ++i) {
-		int node_type;
 		int region;
 
-		node_type = get_node_type(gator_events_ccn504_event[i]);
+		if (!gator_events_ccn504_enabled[i]) {
+			continue;
+		}
+
 		region = get_region(gator_events_ccn504_event[i]);
 
-		//printk(KERN_ERR "%s(%s:%i) writel %x %x\n", __FUNCTION__, __FILE__, __LINE__, 0, region*REGION_SIZE + PMU_EVENT_SEL);
 		writel(0, gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL);
 	}
 
 	// Clear dt_config
-	for (i = 0; i < 11; ++i) {
-		//printk(KERN_ERR "%s(%s:%i) writel %x %x\n", __FUNCTION__, __FILE__, __LINE__, 0, (REGION_XP + i)*REGION_SIZE + DT_CONFIG);
+	for (i = 0; i < NUM_XPS; ++i) {
 		writel(0, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONFIG);
 	}
 }
@@ -194,27 +274,20 @@
 {
 	int i;
 	int len = 0;
+	int value;
 
-	if (!on_primary_core()) {
+	if (!on_primary_core() || !gator_events_ccn504_global_enabled) {
 		return 0;
 	}
 
 	// Verify the pmsr register is zero
-	//i = 0;
-	while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) != 0) {
-		//++i;
-	}
-	//printk(KERN_ERR "%s(%s:%i) %i\n", __FUNCTION__, __FILE__, __LINE__, i);
+	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
-	//i = 0;
-	while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) == 0) {
-		//++i;
-	}
-	//printk(KERN_ERR "%s(%s:%i) %i\n", __FUNCTION__, __FILE__, __LINE__, i);
+	while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) == 0);
 
 	// Read the shadow registers
 	for (i = 0; i < CNTMAX; ++i) {
@@ -222,8 +295,12 @@
 			continue;
 		}
 
-		gator_events_ccn504_buffer[len++] = gator_events_ccn504_key[i];
-		gator_events_ccn504_buffer[len++] = readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + (i == CCNT ? PMCCNTRSR : PMEVCNTSR0 + 8*i));
+		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?
 	}
@@ -231,20 +308,12 @@
 	// 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 void __maybe_unused gator_events_ccn504_enumerate(int pos, int size)
-{
-	int i;
-	u32 oly_id;
-
-	for (i = pos; i < pos + size; ++i) {
-		oly_id = readl(gator_events_ccn504_base + i*REGION_SIZE + OLY_ID);
-		printk(KERN_ERR "%s(%s:%i) %i %08x\n", __FUNCTION__, __FILE__, __LINE__, i, oly_id);
-	}
-}
-
 static struct gator_interface gator_events_ccn504_interface = {
 	.shutdown = gator_events_ccn504_create_shutdown,
 	.create_files = gator_events_ccn504_create_files,
@@ -263,36 +332,9 @@
 
 	gator_events_ccn504_base = ioremap(ccn504_addr, NUM_REGIONS*REGION_SIZE);
 	if (gator_events_ccn504_base == NULL) {
-		printk(KERN_ERR "%s(%s:%i) ioremap returned NULL\n", __FUNCTION__, __FILE__, __LINE__);
+		printk(KERN_ERR "gator: ioremap returned NULL\n");
 		return -1;
 	}
-	//printk(KERN_ERR "%s(%s:%i)\n", __FUNCTION__, __FILE__, __LINE__);
-
-	// Test - can memory be read
-	{
-		//gator_events_ccn504_enumerate(0, NUM_REGIONS);
-
-#if 0
-		// DT
-		gator_events_ccn504_enumerate(1, 1);
-		// HN-F
-		gator_events_ccn504_enumerate(32, 8);
-		// XP
-		gator_events_ccn504_enumerate(64, 11);
-		// RN-I
-		gator_events_ccn504_enumerate(128, 1);
-		gator_events_ccn504_enumerate(130, 1);
-		gator_events_ccn504_enumerate(134, 1);
-		gator_events_ccn504_enumerate(140, 1);
-		gator_events_ccn504_enumerate(144, 1);
-		gator_events_ccn504_enumerate(148, 1);
-		// SBAS
-		gator_events_ccn504_enumerate(129, 1);
-		gator_events_ccn504_enumerate(137, 1);
-		gator_events_ccn504_enumerate(139, 1);
-		gator_events_ccn504_enumerate(147, 1);
-#endif
-	}
 
 	for (i = 0; i < CNTMAX; ++i) {
 		gator_events_ccn504_enabled[i] = 0;
@@ -302,5 +344,3 @@
 
 	return gator_events_install(&gator_events_ccn504_interface);
 }
-
-gator_events_init(gator_events_ccn504_init);
diff --git a/drivers/gator/gator_events_irq.c b/drivers/gator/gator_events_irq.c
index b4df7fa..b11879a 100644
--- a/drivers/gator/gator_events_irq.c
+++ b/drivers/gator/gator_events_irq.c
@@ -163,5 +163,3 @@
 
 	return gator_events_install(&gator_events_irq_interface);
 }
-
-gator_events_init(gator_events_irq_init);
diff --git a/drivers/gator/gator_events_l2c-310.c b/drivers/gator/gator_events_l2c-310.c
index 21aa4a2..ee521af 100644
--- a/drivers/gator/gator_events_l2c-310.c
+++ b/drivers/gator/gator_events_l2c-310.c
@@ -206,5 +206,3 @@
 
 	return gator_events_install(&gator_events_l2c310_interface);
 }
-
-gator_events_init(gator_events_l2c310_init);
diff --git a/drivers/gator/gator_events_mali_4xx.c b/drivers/gator/gator_events_mali_4xx.c
index dd275f7..6719c1e 100644
--- a/drivers/gator/gator_events_mali_4xx.c
+++ b/drivers/gator/gator_events_mali_4xx.c
@@ -415,25 +415,12 @@
 	int i;
 	int core_id;
 
-	mali_osk_fb_control_set_type *mali_set_fb_event;
 	mali_profiling_control_type *mali_control;
 
 	init_counters(COUNTER_L2_0_C0, COUNTER_L2_0_C0 + (2 * n_l2_cores) - 1);
 	init_counters(COUNTER_VP_0_C0, COUNTER_VP_0_C0 + (2 * n_vp_cores) - 1);
 	init_counters(COUNTER_FP_0_C0, COUNTER_FP_0_C0 + (2 * n_fp_cores) - 1);
 
-	mali_set_fb_event = symbol_get(_mali_osk_fb_control_set);
-
-	if (mali_set_fb_event) {
-		pr_debug("gator: mali online _mali_osk_fb_control_set symbol @ %p\n", mali_set_fb_event);
-
-		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");
-	}
-
 	/* Generic control interface for Mali DDK. */
 	mali_control = symbol_get(_mali_profiling_control);
 	if (mali_control) {
@@ -491,7 +478,6 @@
 static void mali_counter_deinitialize(void)
 {
 	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;
 
 	mali_set_hw_event = symbol_get(_mali_profiling_set_event);
@@ -509,23 +495,11 @@
 		printk("gator: mali offline _mali_profiling_set_event symbol not found\n");
 	}
 
-	mali_set_fb_event = symbol_get(_mali_osk_fb_control_set);
-
-	if (mali_set_fb_event) {
-		pr_debug("gator: mali offline _mali_osk_fb_control_set symbol @ %p\n", mali_set_fb_event);
-
-		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);
 
 	if (mali_control) {
-		pr_debug("gator: mali offline _mali_profiling_control symbol @ %p\n", mali_set_fb_event);
+		pr_debug("gator: mali offline _mali_profiling_control symbol @ %p\n", mali_control);
 
 		/* Reset the DDK state - disable counter collection */
 		mali_control(SW_COUNTER_ENABLE, 0);
@@ -747,5 +721,3 @@
 
 	return gator_events_install(&gator_events_mali_interface);
 }
-
-gator_events_init(gator_events_mali_init);
diff --git a/drivers/gator/gator_events_mali_common.c b/drivers/gator/gator_events_mali_common.c
index 5a98b37..466ca16 100644
--- a/drivers/gator/gator_events_mali_common.c
+++ b/drivers/gator/gator_events_mali_common.c
@@ -28,7 +28,7 @@
 	}
 }
 
-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)
+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)
 {
 	int err;
 	char buf[255];
@@ -56,6 +56,13 @@
 			pr_debug("gator: Mali-T6xx: error calling gatorfs_create_ro_ulong for: %s (%s)", event_name, buf);
 			return -1;
 		}
+		if (event != NULL) {
+			err = gatorfs_create_ulong(sb, dir, "event", event);
+			if (err != 0) {
+				pr_debug("gator: Mali-T6xx: error calling gatorfs_create_ro_ulong for: %s (%s)", event_name, buf);
+				return -1;
+			}
+		}
 	}
 
 	return 0;
diff --git a/drivers/gator/gator_events_mali_common.h b/drivers/gator/gator_events_mali_common.h
index d67ee2d..509f9b6 100644
--- a/drivers/gator/gator_events_mali_common.h
+++ b/drivers/gator/gator_events_mali_common.h
@@ -43,7 +43,6 @@
  * Mali-4xx
  */
 typedef int mali_profiling_set_event_type(unsigned int, 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 *);
 
@@ -51,7 +50,6 @@
  * Driver entry points for functions called directly by gator.
  */
 extern int _mali_profiling_set_event(unsigned int, 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 *);
 
@@ -75,7 +73,7 @@
  *
  * @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);
+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);
 
 /**
  * Initializes the counter array.
diff --git a/drivers/gator/gator_events_mali_t6xx.c b/drivers/gator/gator_events_mali_t6xx.c
index 2576a99..7bf7d6a 100644
--- a/drivers/gator/gator_events_mali_t6xx.c
+++ b/drivers/gator/gator_events_mali_t6xx.c
@@ -109,12 +109,14 @@
 #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)
+#define FILMSTRIP (NUMBER_OF_TIMELINE_EVENTS + NUMBER_OF_SOFTWARE_COUNTERS + NUMBER_OF_ACCUMULATORS)
+#define NUMBER_OF_EVENTS (NUMBER_OF_TIMELINE_EVENTS + NUMBER_OF_SOFTWARE_COUNTERS + NUMBER_OF_ACCUMULATORS + 1)
 
 /*
  * gatorfs variables for counter enable state
  */
 static 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
@@ -285,28 +287,37 @@
 	 */
 	int counter_index = 0;
 	const char *mali_name = gator_mali_get_mali_name();
+	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]) != 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]) != 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]) != 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) {
+			return -1;
+		}
+		symbol_put(_mali_profiling_control);
+	}
+
 	return 0;
 }
 
@@ -350,6 +361,7 @@
 static int start(void)
 {
 	unsigned int cnt;
+	mali_profiling_control_type *mali_control;
 
 	/* Clean all data for the next capture */
 	for (cnt = 0; cnt < NUMBER_OF_TIMELINE_EVENTS; cnt++) {
@@ -370,6 +382,30 @@
 		return -1;
 	}
 
+	/* 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 enabled = counters[FILMSTRIP].enabled ? 1 : 0;
+		unsigned int rate = filmstrip_event & 0xff;
+		unsigned int resize_factor = (filmstrip_event >> 8) & 0xff;
+
+		pr_debug("gator: mali online _mali_profiling_control symbol @ %p\n", mali_control);
+
+#define FBDUMP_CONTROL_ENABLE (1)
+#define FBDUMP_CONTROL_RATE (2)
+#define FBDUMP_CONTROL_RESIZE_FACTOR (4)
+		mali_control(FBDUMP_CONTROL_ENABLE, enabled);
+		mali_control(FBDUMP_CONTROL_RATE, rate);
+		mali_control(FBDUMP_CONTROL_RESIZE_FACTOR, resize_factor);
+
+		pr_debug("gator: sent mali_control enabled=%d, rate=%d, resize_factor=%d\n", enabled, rate, resize_factor);
+
+		symbol_put(_mali_profiling_control);
+	} else {
+		printk("gator: mali online _mali_profiling_control symbol not found\n");
+	}
+
 	/*
 	 * 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'.
@@ -382,6 +418,8 @@
 
 static void stop(void)
 {
+	mali_profiling_control_type *mali_control;
+
 	pr_debug("gator: Mali-T6xx: stop\n");
 
 	/*
@@ -402,6 +440,18 @@
 
 	GATOR_UNREGISTER_TRACE(mali_total_alloc_pages_change);
 	pr_debug("gator: Mali-T6xx: mali_total_alloc_pages_change tracepoint deactivated\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", mali_control);
+
+		mali_control(FBDUMP_CONTROL_ENABLE, 0);
+
+		symbol_put(_mali_profiling_control);
+	} else {
+		printk("gator: mali offline _mali_profiling_control symbol not found\n");
+	}
 }
 
 static int read(int **buffer)
@@ -508,5 +558,3 @@
 
 	return gator_events_install(&gator_events_mali_t6xx_interface);
 }
-
-gator_events_init(gator_events_mali_t6xx_init);
diff --git a/drivers/gator/gator_events_mali_t6xx_hw.c b/drivers/gator/gator_events_mali_t6xx_hw.c
index f557350..e406991 100644
--- a/drivers/gator/gator_events_mali_t6xx_hw.c
+++ b/drivers/gator/gator_events_mali_t6xx_hw.c
@@ -63,6 +63,8 @@
 static kbase_va_free_type *kbase_va_free_symbol;
 static kbase_destroy_context_type *kbase_destroy_context_symbol;
 
+static long shader_present_low = 0;
+
 /** The interval between reads, in ns.
  *
  * Earlier we introduced
@@ -496,6 +498,7 @@
 	mali_error err;
 	int cnt;
 	u16 bitmask[] = { 0, 0, 0, 0 };
+	unsigned long long shadersPresent = 0;
 
 	/* Setup HW counters */
 	num_hardware_counters_enabled = 0;
@@ -539,6 +542,11 @@
 			goto out;
 		}
 
+
+		/* See if we can get the number of shader cores */
+		shadersPresent = kbdevice->shader_present_bitmap;
+		shader_present_low = (unsigned long)shadersPresent;
+
 		/*
 		 * The amount of memory needed to store the dump (bytes)
 		 * DUMP_SIZE = number of core groups
@@ -679,21 +687,41 @@
 			kbase_device_busy = false;
 
 			if (success == MALI_TRUE) {
+				/* Cycle through hardware counters and accumulate totals */
 				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;
+						const char* block_base_address = (char*)kernel_dump_buffer + vithar_blocks[block];
 
+						/* If counter belongs to shader block need to take into account all cores */
 						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);
+							int i = 0;
+							int shader_core_count = 0;
+							value = 0;
+
+							for (i = 0; i < 4; i++) {
+								if ((shader_present_low >> i) & 1) {
+									value += *((u32*) (block_base_address + (0x100 * i)) + counter_offset);
+									shader_core_count++;
+								}
+							}
+
+							for (i = 0; i < 4; i++) {
+								if((shader_present_low >> (i+4)) & 1) {
+									value += *((u32*)(block_base_address + (0x100 * i) + 0x800) + counter_offset);
+									shader_core_count++;
+								}
+							}
+
+							/* Need to total by number of cores to produce an average */
+							if (shader_core_count != 0) {
+								value /= shader_core_count;
+							}
+						} else {
+							value = *((u32*)block_base_address + counter_offset);
 						}
 
 						counter_dump[len++] = counter->key;
@@ -727,7 +755,7 @@
 	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)
+		if (gator_mali_create_file_system(mali_name, hardware_counter_names[counter_index], sb, root, &counters[event], NULL) != 0)
 			return -1;
 		counter_index++;
 	}
@@ -754,5 +782,3 @@
 
 	return gator_events_install(&gator_events_mali_t6xx_interface);
 }
-
-gator_events_init(gator_events_mali_t6xx_hw_init);
diff --git a/drivers/gator/gator_events_meminfo.c b/drivers/gator/gator_events_meminfo.c
index c1e360d..451290d 100644
--- a/drivers/gator/gator_events_meminfo.c
+++ b/drivers/gator/gator_events_meminfo.c
@@ -8,27 +8,62 @@
  */
 
 #include "gator.h"
+
+#include <linux/hardirq.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
 #include <linux/workqueue.h>
 #include <trace/events/kmem.h>
-#include <linux/hardirq.h>
 
-#define MEMINFO_MEMFREE		0
-#define MEMINFO_MEMUSED		1
-#define MEMINFO_BUFFERRAM	2
-#define MEMINFO_TOTAL		3
+enum {
+	MEMINFO_MEMFREE,
+	MEMINFO_MEMUSED,
+	MEMINFO_BUFFERRAM,
+	MEMINFO_TOTAL,
+};
 
-static ulong meminfo_global_enabled;
+enum {
+	PROC_SIZE,
+	PROC_SHARE,
+	PROC_TEXT,
+	PROC_DATA,
+	PROC_COUNT,
+};
+
+static const char * const meminfo_names[] = {
+	"Linux_meminfo_memfree",
+	"Linux_meminfo_memused",
+	"Linux_meminfo_bufferram",
+};
+
+static const char * const proc_names[] = {
+	"Linux_proc_statm_size",
+	"Linux_proc_statm_share",
+	"Linux_proc_statm_text",
+	"Linux_proc_statm_data",
+};
+
+static bool meminfo_global_enabled;
 static ulong meminfo_enabled[MEMINFO_TOTAL];
-static ulong meminfo_key[MEMINFO_TOTAL];
-static unsigned long long meminfo_buffer[MEMINFO_TOTAL * 2];
+static ulong meminfo_keys[MEMINFO_TOTAL];
+static long long meminfo_buffer[2 * (MEMINFO_TOTAL + 2)];
 static int meminfo_length = 0;
-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);
+static bool proc_global_enabled;
+static ulong proc_enabled[PROC_COUNT];
+static ulong proc_keys[PROC_COUNT];
+static DEFINE_PER_CPU(long long, proc_buffer[2 * (PROC_COUNT + 3)]);
+
+static int gator_meminfo_func(void *data);
+static bool gator_meminfo_run;
+// Initialize semaphore unlocked to initialize memory values
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
+static DECLARE_MUTEX(gator_meminfo_sem);
+#else
+static DEFINE_SEMAPHORE(gator_meminfo_sem);
+#endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
 GATOR_DEFINE_PROBE(mm_page_free_direct, TP_PROTO(struct page *page, unsigned int order))
@@ -36,7 +71,7 @@
 GATOR_DEFINE_PROBE(mm_page_free, TP_PROTO(struct page *page, unsigned int order))
 #endif
 {
-	mem_event++;
+	up(&gator_meminfo_sem);
 }
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
@@ -45,12 +80,12 @@
 GATOR_DEFINE_PROBE(mm_page_free_batched, TP_PROTO(struct page *page, int cold))
 #endif
 {
-	mem_event++;
+	up(&gator_meminfo_sem);
 }
 
 GATOR_DEFINE_PROBE(mm_page_alloc, TP_PROTO(struct page *page, unsigned int order, gfp_t gfp_flags, int migratetype))
 {
-	mem_event++;
+	up(&gator_meminfo_sem);
 }
 
 static int gator_events_meminfo_create_files(struct super_block *sb, struct dentry *root)
@@ -59,24 +94,21 @@
 	int i;
 
 	for (i = 0; i < MEMINFO_TOTAL; i++) {
-		switch (i) {
-		case MEMINFO_MEMFREE:
-			dir = gatorfs_mkdir(sb, root, "Linux_meminfo_memfree");
-			break;
-		case MEMINFO_MEMUSED:
-			dir = gatorfs_mkdir(sb, root, "Linux_meminfo_memused");
-			break;
-		case MEMINFO_BUFFERRAM:
-			dir = gatorfs_mkdir(sb, root, "Linux_meminfo_bufferram");
-			break;
-		default:
-			return -1;
-		}
+		dir = gatorfs_mkdir(sb, root, meminfo_names[i]);
 		if (!dir) {
 			return -1;
 		}
 		gatorfs_create_ulong(sb, dir, "enabled", &meminfo_enabled[i]);
-		gatorfs_create_ro_ulong(sb, dir, "key", &meminfo_key[i]);
+		gatorfs_create_ro_ulong(sb, dir, "key", &meminfo_keys[i]);
+	}
+
+	for (i = 0; i < PROC_COUNT; ++i) {
+		dir = gatorfs_mkdir(sb, root, proc_names[i]);
+		if (!dir) {
+			return -1;
+		}
+		gatorfs_create_ulong(sb, dir, "enabled", &proc_enabled[i]);
+		gatorfs_create_ro_ulong(sb, dir, "key", &proc_keys[i]);
 	}
 
 	return 0;
@@ -86,13 +118,26 @@
 {
 	int i;
 
-	new_data_avail = true;
+	new_data_avail = false;
+	meminfo_global_enabled = 0;
 	for (i = 0; i < MEMINFO_TOTAL; i++) {
 		if (meminfo_enabled[i]) {
 			meminfo_global_enabled = 1;
+			break;
 		}
 	}
 
+	proc_global_enabled = 0;
+	for (i = 0; i < PROC_COUNT; ++i) {
+		if (proc_enabled[i]) {
+			proc_global_enabled = 1;
+			break;
+		}
+	}
+	if (meminfo_enabled[MEMINFO_MEMUSED]) {
+		proc_global_enabled = 1;
+	}
+
 	if (meminfo_global_enabled == 0)
 		return 0;
 
@@ -111,9 +156,16 @@
 	if (GATOR_REGISTER_TRACE(mm_page_alloc))
 		goto mm_page_alloc_exit;
 
-	setup_timer(&meminfo_wake_up_timer, meminfo_wake_up_handler, 0);
+	// Start worker thread
+	gator_meminfo_run = true;
+	// Since the mutex starts unlocked, memory values will be initialized
+	if (IS_ERR(kthread_run(gator_meminfo_func, NULL, "gator_meminfo")))
+		goto kthread_run_exit;
+
 	return 0;
 
+kthread_run_exit:
+	GATOR_UNREGISTER_TRACE(mm_page_alloc);
 mm_page_alloc_exit:
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
 	GATOR_UNREGISTER_TRACE(mm_pagevec_free);
@@ -132,8 +184,6 @@
 
 static void gator_events_meminfo_stop(void)
 {
-	int i;
-
 	if (meminfo_global_enabled) {
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
 		GATOR_UNREGISTER_TRACE(mm_page_free_direct);
@@ -144,68 +194,75 @@
 #endif
 		GATOR_UNREGISTER_TRACE(mm_page_alloc);
 
-		del_timer_sync(&meminfo_wake_up_timer);
-	}
-
-	meminfo_global_enabled = 0;
-	for (i = 0; i < MEMINFO_TOTAL; i++) {
-		meminfo_enabled[i] = 0;
+		// Stop worker thread
+		gator_meminfo_run = false;
+		up(&gator_meminfo_sem);
 	}
 }
 
 // Must be run in process context as the kernel function si_meminfo() can sleep
-static void wq_sched_handler(struct work_struct *wsptr)
+static int gator_meminfo_func(void *data)
 {
 	struct sysinfo info;
 	int i, len;
 	unsigned long long value;
 
-	meminfo_length = len = 0;
-
-	si_meminfo(&info);
-	for (i = 0; i < MEMINFO_TOTAL; i++) {
-		if (meminfo_enabled[i]) {
-			switch (i) {
-			case MEMINFO_MEMFREE:
-				value = info.freeram * PAGE_SIZE;
-				break;
-			case MEMINFO_MEMUSED:
-				value = (info.totalram - info.freeram) * PAGE_SIZE;
-				break;
-			case MEMINFO_BUFFERRAM:
-				value = info.bufferram * PAGE_SIZE;
-				break;
-			default:
-				value = 0;
-				break;
-			}
-			meminfo_buffer[len++] = (unsigned long long)meminfo_key[i];
-			meminfo_buffer[len++] = value;
+	for (;;) {
+		if (down_killable(&gator_meminfo_sem)) {
+			break;
 		}
+
+		// Eat up any pending events
+		while (!down_trylock(&gator_meminfo_sem));
+
+		if (!gator_meminfo_run) {
+			break;
+		}
+
+		meminfo_length = len = 0;
+
+		si_meminfo(&info);
+		for (i = 0; i < MEMINFO_TOTAL; i++) {
+			if (meminfo_enabled[i]) {
+				switch (i) {
+				case MEMINFO_MEMFREE:
+					value = info.freeram * PAGE_SIZE;
+					break;
+				case MEMINFO_MEMUSED:
+					// pid -1 means system wide
+					meminfo_buffer[len++] = 1;
+					meminfo_buffer[len++] = -1;
+					// Emit value
+					meminfo_buffer[len++] = meminfo_keys[MEMINFO_MEMUSED];
+					meminfo_buffer[len++] = (info.totalram - info.freeram) * PAGE_SIZE;
+					// Clear pid
+					meminfo_buffer[len++] = 1;
+					meminfo_buffer[len++] = 0;
+					continue;
+				case MEMINFO_BUFFERRAM:
+					value = info.bufferram * PAGE_SIZE;
+					break;
+				default:
+					value = 0;
+					break;
+				}
+				meminfo_buffer[len++] = meminfo_keys[i];
+				meminfo_buffer[len++] = value;
+			}
+		}
+
+		meminfo_length = len;
+		new_data_avail = true;
 	}
 
-	meminfo_length = len;
-	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);
+	return 0;
 }
 
 static int gator_events_meminfo_read(long long **buffer)
 {
-	static unsigned int last_mem_event = 0;
-
 	if (!on_primary_core() || !meminfo_global_enabled)
 		return 0;
 
-	if (last_mem_event != mem_event) {
-		last_mem_event = mem_event;
-		mod_timer(&meminfo_wake_up_timer, jiffies + 1);
-	}
-
 	if (!new_data_avail)
 		return 0;
 
@@ -217,11 +274,97 @@
 	return meminfo_length;
 }
 
+static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct *task)
+{
+	struct mm_struct *mm;
+	u64 share = 0;
+	int i;
+	long long value;
+	int len = 0;
+	int cpu = get_physical_cpu();
+	long long *buf = per_cpu(proc_buffer, cpu);
+
+	if (!proc_global_enabled) {
+		return 0;
+	}
+
+	// Collect the memory stats of the process instead of the thread
+	if (task->group_leader != NULL) {
+		task = task->group_leader;
+	}
+
+	// get_task_mm/mmput is not needed in this context because the task and it's mm are required as part of the sched_switch
+	mm = task->mm;
+	if (mm == NULL) {
+		return 0;
+	}
+
+	// Derived from task_statm in fs/proc/task_mmu.c
+	if (meminfo_enabled[MEMINFO_MEMUSED] || proc_enabled[PROC_SHARE]) {
+		share = get_mm_counter(mm,
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32)
+							   file_rss
+#else
+							   MM_FILEPAGES
+#endif
+							   );
+	}
+
+	// key of 1 indicates a pid
+	buf[len++] = 1;
+	buf[len++] = task->pid;
+
+	for (i = 0; i < PROC_COUNT; ++i) {
+		if (proc_enabled[i]) {
+			switch (i) {
+			case PROC_SIZE:
+				value = mm->total_vm;
+				break;
+			case PROC_SHARE:
+				value = share;
+				break;
+			case PROC_TEXT:
+				value = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) >> PAGE_SHIFT;
+				break;
+			case PROC_DATA:
+				value = mm->total_vm - mm->shared_vm;
+				break;
+			}
+
+			buf[len++] = proc_keys[i];
+			buf[len++] = value * PAGE_SIZE;
+		}
+	}
+
+	if (meminfo_enabled[MEMINFO_MEMUSED]) {
+		value = share + get_mm_counter(mm,
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32)
+									   anon_rss
+#else
+									   MM_ANONPAGES
+#endif
+									   );
+		// Send resident for this pid
+		buf[len++] = meminfo_keys[MEMINFO_MEMUSED];
+		buf[len++] = value * PAGE_SIZE;
+	}
+
+	// Clear pid
+	buf[len++] = 1;
+	buf[len++] = 0;
+
+	if (buffer)
+		*buffer = buf;
+
+	return len;
+}
+
 static struct gator_interface gator_events_meminfo_interface = {
 	.create_files = gator_events_meminfo_create_files,
 	.start = gator_events_meminfo_start,
 	.stop = gator_events_meminfo_stop,
 	.read64 = gator_events_meminfo_read,
+	.read_proc = gator_events_meminfo_read_proc,
 };
 
 int gator_events_meminfo_init(void)
@@ -231,10 +374,14 @@
 	meminfo_global_enabled = 0;
 	for (i = 0; i < MEMINFO_TOTAL; i++) {
 		meminfo_enabled[i] = 0;
-		meminfo_key[i] = gator_events_get_key();
+		meminfo_keys[i] = gator_events_get_key();
+	}
+
+	proc_global_enabled = 0;
+	for (i = 0; i < PROC_COUNT; ++i) {
+		proc_enabled[i] = 0;
+		proc_keys[i] = gator_events_get_key();
 	}
 
 	return gator_events_install(&gator_events_meminfo_interface);
 }
-
-gator_events_init(gator_events_meminfo_init);
diff --git a/drivers/gator/gator_events_mmaped.c b/drivers/gator/gator_events_mmaped.c
deleted file mode 100644
index f7670f6..0000000
--- a/drivers/gator/gator_events_mmaped.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Example events provider
- *
- * Copyright (C) ARM Limited 2010-2013. 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.
- *
- * Similar entries to those below must be present in the events.xml file.
- * To add them to the events.xml, create an events-mmap.xml with the 
- * following contents and rebuild gatord:
- *
- * <counter_set name="mmaped_cnt" count="3"/>
- * <category name="mmaped" counter_set="mmaped_cnt" per_cpu="no">
- *   <event event="0x0" title="Simulated1" name="Sine" display="maximum" average_selection="yes" description="Sort-of-sine"/>
- *   <event event="0x1" title="Simulated2" name="Triangle" display="maximum" average_selection="yes" description="Triangular wave"/>
- *   <event event="0x2" title="Simulated3" name="PWM" display="maximum" average_selection="yes" description="PWM Signal"/>
- * </category>
- */
-
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/ratelimit.h>
-
-#include "gator.h"
-
-#define MMAPED_COUNTERS_NUM 3
-
-static struct {
-	unsigned long enabled;
-	unsigned long event;
-	unsigned long key;
-} mmaped_counters[MMAPED_COUNTERS_NUM];
-
-static int mmaped_buffer[MMAPED_COUNTERS_NUM * 2];
-
-#ifdef TODO
-static void __iomem *mmaped_base;
-#endif
-
-#ifndef TODO
-static s64 prev_time;
-#endif
-
-/* Adds mmaped_cntX directories and enabled, event, and key files to /dev/gator/events */
-static int gator_events_mmaped_create_files(struct super_block *sb,
-					    struct dentry *root)
-{
-	int i;
-
-	for (i = 0; i < MMAPED_COUNTERS_NUM; i++) {
-		char buf[16];
-		struct dentry *dir;
-
-		snprintf(buf, sizeof(buf), "mmaped_cnt%d", i);
-		dir = gatorfs_mkdir(sb, root, buf);
-		if (WARN_ON(!dir))
-			return -1;
-		gatorfs_create_ulong(sb, dir, "enabled",
-				     &mmaped_counters[i].enabled);
-		gatorfs_create_ulong(sb, dir, "event",
-				     &mmaped_counters[i].event);
-		gatorfs_create_ro_ulong(sb, dir, "key",
-					&mmaped_counters[i].key);
-	}
-
-	return 0;
-}
-
-static int gator_events_mmaped_start(void)
-{
-#ifdef TODO
-	for (i = 0; i < MMAPED_COUNTERS_NUM; i++)
-		writel(mmaped_counters[i].event,
-		       mmaped_base + COUNTERS_CONFIG_OFFSET[i]);
-
-	writel(ENABLED, COUNTERS_CONTROL_OFFSET);
-#endif
-
-#ifndef TODO
-	struct timespec ts;
-	getnstimeofday(&ts);
-	prev_time = timespec_to_ns(&ts);
-#endif
-
-	return 0;
-}
-
-static void gator_events_mmaped_stop(void)
-{
-#ifdef TODO
-	writel(DISABLED, COUNTERS_CONTROL_OFFSET);
-#endif
-}
-
-#ifndef TODO
-/* This function "simulates" counters, generating values of fancy
- * functions like sine or triangle... */
-static int mmaped_simulate(int counter, int delta_in_us)
-{
-	int result = 0;
-
-	switch (counter) {
-	case 0:		/* sort-of-sine */
-		{
-			static int t = 0;
-			int x;
-
-			t += delta_in_us;
-			if (t > 2048000)
-				t = 0;
-
-			if (t % 1024000 < 512000)
-				x = 512000 - (t % 512000);
-			else
-				x = t % 512000;
-
-			result = 32 * x / 512000;
-			result = result * result;
-
-			if (t < 1024000)
-				result = 1922 - result;
-		}
-		break;
-	case 1:		/* triangle */
-		{
-			static int v, d = 1;
-
-			v = v + d * delta_in_us;
-			if (v < 0) {
-				v = 0;
-				d = 1;
-			} else if (v > 1000000) {
-				v = 1000000;
-				d = -1;
-			}
-
-			result = v;
-		}
-		break;
-	case 2:		/* PWM signal */
-		{
-			static int dc, x, t = 0;
-
-			t += delta_in_us;
-			if (t > 1000000)
-				t = 0;
-			if (x / 1000000 != (x + delta_in_us) / 1000000)
-				dc = (dc + 100000) % 1000000;
-			x += delta_in_us;
-
-			result = t < dc ? 0 : 10;
-		}
-		break;
-	}
-
-	return result;
-}
-#endif
-
-static int gator_events_mmaped_read(int **buffer)
-{
-	int i;
-	int len = 0;
-#ifndef TODO
-	int delta_in_us;
-	struct timespec ts;
-	s64 time;
-#endif
-
-	/* System wide counters - read from one core only */
-	if (!on_primary_core())
-		return 0;
-
-#ifndef TODO
-	getnstimeofday(&ts);
-	time = timespec_to_ns(&ts);
-	delta_in_us = (int)(time - prev_time) / 1000;
-	prev_time = time;
-#endif
-
-	for (i = 0; i < MMAPED_COUNTERS_NUM; i++) {
-		if (mmaped_counters[i].enabled) {
-			mmaped_buffer[len++] = mmaped_counters[i].key;
-#ifdef TODO
-			mmaped_buffer[len++] =
-			    readl(mmaped_base + COUNTERS_VALUE_OFFSET[i]);
-#else
-			mmaped_buffer[len++] =
-			    mmaped_simulate(mmaped_counters[i].event,
-					    delta_in_us);
-#endif
-		}
-	}
-
-	if (buffer)
-		*buffer = mmaped_buffer;
-
-	return len;
-}
-
-static struct gator_interface gator_events_mmaped_interface = {
-	.create_files = gator_events_mmaped_create_files,
-	.start = gator_events_mmaped_start,
-	.stop = gator_events_mmaped_stop,
-	.read = gator_events_mmaped_read,
-};
-
-/* Must not be static! */
-int __init gator_events_mmaped_init(void)
-{
-	int i;
-
-#ifdef TODO
-	mmaped_base = ioremap(COUNTERS_PHYS_ADDR, SZ_4K);
-	if (!mmaped_base)
-		return -ENOMEM;
-#endif
-
-	for (i = 0; i < MMAPED_COUNTERS_NUM; i++) {
-		mmaped_counters[i].enabled = 0;
-		mmaped_counters[i].key = gator_events_get_key();
-	}
-
-	return gator_events_install(&gator_events_mmaped_interface);
-}
-
-gator_events_init(gator_events_mmaped_init);
diff --git a/drivers/gator/gator_events_mmapped.c b/drivers/gator/gator_events_mmapped.c
new file mode 100644
index 0000000..f055e48
--- /dev/null
+++ b/drivers/gator/gator_events_mmapped.c
@@ -0,0 +1,209 @@
+/*
+ * Example events provider
+ *
+ * Copyright (C) ARM Limited 2010-2013. 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.
+ *
+ * Similar entries to those below must be present in the events.xml file.
+ * To add them to the events.xml, create an events-mmap.xml with the 
+ * following contents and rebuild gatord:
+ *
+ * <counter_set name="mmapped_cnt" count="3"/>
+ * <category name="mmapped" counter_set="mmapped_cnt" per_cpu="no">
+ *   <event event="0x0" title="Simulated1" name="Sine" display="maximum" average_selection="yes" description="Sort-of-sine"/>
+ *   <event event="0x1" title="Simulated2" name="Triangle" display="maximum" average_selection="yes" description="Triangular wave"/>
+ *   <event event="0x2" title="Simulated3" name="PWM" display="maximum" average_selection="yes" description="PWM Signal"/>
+ * </category>
+ *
+ * When adding custom events, be sure do the following
+ * - add any needed .c files to the gator driver Makefile
+ * - call gator_events_install in the events init function
+ * - add the init function to GATOR_EVENTS_LIST in gator_main.c
+ * - add a new events-*.xml file to the gator daemon and rebuild
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ratelimit.h>
+
+#include "gator.h"
+
+#define MMAPPED_COUNTERS_NUM 3
+
+static int mmapped_global_enabled;
+
+static struct {
+	unsigned long enabled;
+	unsigned long event;
+	unsigned long key;
+} mmapped_counters[MMAPPED_COUNTERS_NUM];
+
+static int mmapped_buffer[MMAPPED_COUNTERS_NUM * 2];
+
+static s64 prev_time;
+
+/* Adds mmapped_cntX directories and enabled, event, and key files to /dev/gator/events */
+static int gator_events_mmapped_create_files(struct super_block *sb,
+					    struct dentry *root)
+{
+	int i;
+
+	for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) {
+		char buf[16];
+		struct dentry *dir;
+
+		snprintf(buf, sizeof(buf), "mmapped_cnt%d", i);
+		dir = gatorfs_mkdir(sb, root, buf);
+		if (WARN_ON(!dir))
+			return -1;
+		gatorfs_create_ulong(sb, dir, "enabled",
+				     &mmapped_counters[i].enabled);
+		gatorfs_create_ulong(sb, dir, "event",
+				     &mmapped_counters[i].event);
+		gatorfs_create_ro_ulong(sb, dir, "key",
+					&mmapped_counters[i].key);
+	}
+
+	return 0;
+}
+
+static int gator_events_mmapped_start(void)
+{
+	int i;
+	struct timespec ts;
+
+	getnstimeofday(&ts);
+	prev_time = timespec_to_ns(&ts);
+
+	mmapped_global_enabled = 0;
+	for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) {
+		if (mmapped_counters[i].enabled) {
+			mmapped_global_enabled = 1;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static void gator_events_mmapped_stop(void)
+{
+}
+
+/* This function "simulates" counters, generating values of fancy
+ * functions like sine or triangle... */
+static int mmapped_simulate(int counter, int delta_in_us)
+{
+	int result = 0;
+
+	switch (counter) {
+	case 0:		/* sort-of-sine */
+		{
+			static int t = 0;
+			int x;
+
+			t += delta_in_us;
+			if (t > 2048000)
+				t = 0;
+
+			if (t % 1024000 < 512000)
+				x = 512000 - (t % 512000);
+			else
+				x = t % 512000;
+
+			result = 32 * x / 512000;
+			result = result * result;
+
+			if (t < 1024000)
+				result = 1922 - result;
+		}
+		break;
+	case 1:		/* triangle */
+		{
+			static int v, d = 1;
+
+			v = v + d * delta_in_us;
+			if (v < 0) {
+				v = 0;
+				d = 1;
+			} else if (v > 1000000) {
+				v = 1000000;
+				d = -1;
+			}
+
+			result = v;
+		}
+		break;
+	case 2:		/* PWM signal */
+		{
+			static int dc, x, t = 0;
+
+			t += delta_in_us;
+			if (t > 1000000)
+				t = 0;
+			if (x / 1000000 != (x + delta_in_us) / 1000000)
+				dc = (dc + 100000) % 1000000;
+			x += delta_in_us;
+
+			result = t < dc ? 0 : 10;
+		}
+		break;
+	}
+
+	return result;
+}
+
+static int gator_events_mmapped_read(int **buffer)
+{
+	int i;
+	int len = 0;
+	int delta_in_us;
+	struct timespec ts;
+	s64 time;
+
+	/* System wide counters - read from one core only */
+	if (!on_primary_core() || !mmapped_global_enabled)
+		return 0;
+
+	getnstimeofday(&ts);
+	time = timespec_to_ns(&ts);
+	delta_in_us = (int)(time - prev_time) / 1000;
+	prev_time = time;
+
+	for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) {
+		if (mmapped_counters[i].enabled) {
+			mmapped_buffer[len++] = mmapped_counters[i].key;
+			mmapped_buffer[len++] =
+			    mmapped_simulate(mmapped_counters[i].event,
+					    delta_in_us);
+		}
+	}
+
+	if (buffer)
+		*buffer = mmapped_buffer;
+
+	return len;
+}
+
+static struct gator_interface gator_events_mmapped_interface = {
+	.create_files = gator_events_mmapped_create_files,
+	.start = gator_events_mmapped_start,
+	.stop = gator_events_mmapped_stop,
+	.read = gator_events_mmapped_read,
+};
+
+/* Must not be static! */
+int __init gator_events_mmapped_init(void)
+{
+	int i;
+
+	for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) {
+		mmapped_counters[i].enabled = 0;
+		mmapped_counters[i].key = gator_events_get_key();
+	}
+
+	return gator_events_install(&gator_events_mmapped_interface);
+}
diff --git a/drivers/gator/gator_events_net.c b/drivers/gator/gator_events_net.c
index 80cdee4..9c8d3a4 100644
--- a/drivers/gator/gator_events_net.c
+++ b/drivers/gator/gator_events_net.c
@@ -73,6 +73,8 @@
 
 static int gator_events_net_create_files(struct super_block *sb, struct dentry *root)
 {
+	// Network counters are not currently supported in RT-Preempt full because mod_timer is used
+#ifndef CONFIG_PREEMPT_RT_FULL
 	struct dentry *dir;
 
 	dir = gatorfs_mkdir(sb, root, "Linux_net_rx");
@@ -88,6 +90,7 @@
 	}
 	gatorfs_create_ulong(sb, dir, "enabled", &nettx_enabled);
 	gatorfs_create_ro_ulong(sb, dir, "key", &nettx_key);
+#endif
 
 	return 0;
 }
@@ -167,5 +170,3 @@
 
 	return gator_events_install(&gator_events_net_interface);
 }
-
-gator_events_init(gator_events_net_init);
diff --git a/drivers/gator/gator_events_perf_pmu.c b/drivers/gator/gator_events_perf_pmu.c
index 53b2d0a5..d472df9 100644
--- a/drivers/gator/gator_events_perf_pmu.c
+++ b/drivers/gator/gator_events_perf_pmu.c
@@ -6,13 +6,18 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/slab.h>
-#include <linux/perf_event.h>
 #include "gator.h"
 
 // gator_events_armvX.c is used for Linux 2.6.x
 #if GATOR_PERF_PMU_SUPPORT
 
+#include <linux/io.h>
+#ifdef CONFIG_OF
+#include <linux/of_address.h>
+#endif
+#include <linux/perf_event.h>
+#include <linux/slab.h>
+
 extern bool event_based_sampling;
 
 // Maximum number of per-core counters - currently reserves enough space for two full hardware PMUs for big.LITTLE
@@ -22,6 +27,9 @@
 // + 1 for the cci-400 cycles counter
 #define UCCNT (CCI_400 + 1)
 
+// Default to 0 if unable to probe the revision which was the previous behavior
+#define DEFAULT_CCI_REVISION 0
+
 // A gator_attr is needed for every counter
 struct gator_attr {
 	// Set once in gator_events_perf_pmu_*_init - the name of the event in the gatorfs
@@ -404,17 +412,81 @@
 	attr->key = gator_events_get_key();
 }
 
+#ifdef CONFIG_OF
+
+static const struct of_device_id arm_cci_matches[] = {
+	{.compatible = "arm,cci-400" },
+	{},
+};
+
+static int probe_cci_revision(void)
+{
+	struct device_node *np;
+	struct resource res;
+	void __iomem *cci_ctrl_base;
+	int rev;
+	int ret = DEFAULT_CCI_REVISION;
+
+	np = of_find_matching_node(NULL, arm_cci_matches);
+	if (!np) {
+		return ret;
+	}
+
+	if (of_address_to_resource(np, 0, &res)) {
+		goto node_put;
+	}
+
+	cci_ctrl_base = ioremap(res.start, resource_size(&res));
+
+	rev = (readl_relaxed(cci_ctrl_base + 0xfe8) >> 4) & 0xf;
+
+	if (rev <= 4) {
+		ret = 0;
+	} else if (rev <= 6) {
+		ret = 1;
+	}
+
+	iounmap(cci_ctrl_base);
+
+ node_put:
+	of_node_put(np);
+
+	return ret;
+}
+
+#else
+
+static int probe_cci_revision(void)
+{
+	return DEFAULT_CCI_REVISION;
+}
+
+#endif
+
 static void gator_events_perf_pmu_cci_init(const int type)
 {
 	int cnt;
+	const char *cci_name;
 
-	strncpy(uc_attrs[uc_attr_count].name, "cci-400_ccnt", sizeof(uc_attrs[uc_attr_count].name));
+	switch (probe_cci_revision()) {
+	case 0:
+		cci_name = "cci-400";
+		break;
+	case 1:
+		cci_name = "cci-400-r1";
+		break;
+	default:
+		pr_debug("gator: unrecognized cci-400 revision\n");
+		return;
+	}
+
+	snprintf(uc_attrs[uc_attr_count].name, sizeof(uc_attrs[uc_attr_count].name), "%s_ccnt", cci_name);
 	uc_attrs[uc_attr_count].type = type;
 	++uc_attr_count;
 
 	for (cnt = 0; cnt < CCI_400; ++cnt, ++uc_attr_count) {
 		struct gator_attr *const attr = &uc_attrs[uc_attr_count];
-		snprintf(attr->name, sizeof(attr->name), "cci-400_cnt%d", cnt);
+		snprintf(attr->name, sizeof(attr->name), "%s_cnt%d", cci_name, cnt);
 		attr->type = type;
 	}
 }
@@ -477,7 +549,7 @@
 		}
 
 		if (pe->pmu != NULL && type == pe->pmu->type) {
-			if (strcmp("CCI", pe->pmu->name) == 0) {
+			if (strcmp("CCI", pe->pmu->name) == 0 || strcmp("CCI_400", pe->pmu->name) == 0) {
 				gator_events_perf_pmu_cci_init(type);
 			} else if ((gator_cpu = gator_find_cpu_by_pmu_name(pe->pmu->name)) != NULL) {
 				found_cpu = true;
@@ -512,5 +584,4 @@
 	return gator_events_install(&gator_events_perf_pmu_interface);
 }
 
-gator_events_init(gator_events_perf_pmu_init);
 #endif
diff --git a/drivers/gator/gator_events_sched.c b/drivers/gator/gator_events_sched.c
index 461a051..29f4e39 100644
--- a/drivers/gator/gator_events_sched.c
+++ b/drivers/gator/gator_events_sched.c
@@ -111,5 +111,3 @@
 
 	return gator_events_install(&gator_events_sched_interface);
 }
-
-gator_events_init(gator_events_sched_init);
diff --git a/drivers/gator/gator_events_scorpion.c b/drivers/gator/gator_events_scorpion.c
index aaf306a..c91db12 100644
--- a/drivers/gator/gator_events_scorpion.c
+++ b/drivers/gator/gator_events_scorpion.c
@@ -666,11 +666,4 @@
 	return gator_events_install(&gator_events_scorpion_interface);
 }
 
-gator_events_init(gator_events_scorpion_init);
-
-#else
-int gator_events_scorpion_init(void)
-{
-	return -1;
-}
 #endif
diff --git a/drivers/gator/gator_main.c b/drivers/gator/gator_main.c
index 7dd70d9..9773ae2 100644
--- a/drivers/gator/gator_main.c
+++ b/drivers/gator/gator_main.c
@@ -8,7 +8,8 @@
  */
 
 // This version must match the gator daemon version
-static unsigned long gator_protocol_version = 16;
+#define PROTOCOL_VERSION 17
+static unsigned long gator_protocol_version = PROTOCOL_VERSION;
 
 #include <linux/slab.h>
 #include <linux/cpu.h>
@@ -22,16 +23,20 @@
 #include <linux/module.h>
 #include <linux/perf_event.h>
 #include <linux/utsname.h>
+#include <linux/kthread.h>
 #include <asm/stacktrace.h>
 #include <asm/uaccess.h>
 
 #include "gator.h"
-#include "gator_events.h"
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
 #error kernels prior to 2.6.32 are not supported
 #endif
 
+#if defined(MODULE) && !defined(CONFIG_MODULES)
+#error Cannot build a module against a kernel that does not support modules. To resolve, either rebuild the kernel to support modules or build gator as part of the kernel.
+#endif
+
 #if !defined(CONFIG_GENERIC_TRACER) && !defined(CONFIG_TRACING)
 #error gator requires the kernel to have CONFIG_GENERIC_TRACER or CONFIG_TRACING defined
 #endif
@@ -44,7 +49,7 @@
 #error gator requires the kernel to have CONFIG_HIGH_RES_TIMERS defined to support PC sampling
 #endif
 
-#if defined(__arm__) && defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) && defined(__arm__) && defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS)
 #error gator requires the kernel to have CONFIG_LOCAL_TIMERS defined on SMP systems
 #endif
 
@@ -87,6 +92,7 @@
 #define MESSAGE_COOKIE      1
 #define MESSAGE_THREAD_NAME 2
 #define HRTIMER_CORE_NAME   3
+#define MESSAGE_LINK        4
 
 #define MESSAGE_GPU_START 1
 #define MESSAGE_GPU_STOP  2
@@ -136,6 +142,7 @@
 
 static unsigned long gator_started;
 static u64 gator_monotonic_started;
+static u64 gator_hibernate_time;
 static unsigned long gator_buffer_opened;
 static unsigned long gator_timer_count;
 static unsigned long gator_response_type;
@@ -147,6 +154,8 @@
 static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait);
 static DECLARE_WAIT_QUEUE_HEAD(gator_annotate_wait);
 static struct timer_list gator_buffer_wake_up_timer;
+static bool gator_buffer_wake_stop;
+static struct task_struct *gator_buffer_wake_thread;
 static LIST_HEAD(gator_events);
 
 static DEFINE_PER_CPU(u64, last_timestamp);
@@ -189,6 +198,34 @@
 // The time after which the buffer should be committed for live display
 static DEFINE_PER_CPU(u64, gator_buffer_commit_time);
 
+// List of all gator events - new events must be added to this list
+#define GATOR_EVENTS_LIST \
+	GATOR_EVENT(gator_events_armv6_init) \
+	GATOR_EVENT(gator_events_armv7_init) \
+	GATOR_EVENT(gator_events_block_init) \
+	GATOR_EVENT(gator_events_ccn504_init) \
+	GATOR_EVENT(gator_events_irq_init) \
+	GATOR_EVENT(gator_events_l2c310_init) \
+	GATOR_EVENT(gator_events_mali_init) \
+	GATOR_EVENT(gator_events_mali_t6xx_hw_init) \
+	GATOR_EVENT(gator_events_mali_t6xx_init) \
+	GATOR_EVENT(gator_events_meminfo_init) \
+	GATOR_EVENT(gator_events_mmapped_init) \
+	GATOR_EVENT(gator_events_net_init) \
+	GATOR_EVENT(gator_events_perf_pmu_init) \
+	GATOR_EVENT(gator_events_sched_init) \
+	GATOR_EVENT(gator_events_scorpion_init) \
+
+#define GATOR_EVENT(EVENT_INIT) __weak int EVENT_INIT(void);
+GATOR_EVENTS_LIST
+#undef GATOR_EVENT
+
+static int (*gator_events_list[])(void) = {
+#define GATOR_EVENT(EVENT_INIT) EVENT_INIT,
+GATOR_EVENTS_LIST
+#undef GATOR_EVENT
+};
+
 /******************************************************************************
  * Application Includes
  ******************************************************************************/
@@ -392,6 +429,21 @@
 	wake_up(&gator_buffer_wait);
 }
 
+static int gator_buffer_wake_func(void *data)
+{
+	while (!gator_buffer_wake_stop) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule();
+		if (gator_buffer_wake_stop) {
+			break;
+		}
+
+		gator_buffer_wake_up(0);
+	}
+
+	return 0;
+}
+
 /******************************************************************************
  * Commit interface
  ******************************************************************************/
@@ -517,7 +569,14 @@
 	marshal_frame(cpu, buftype);
 
 	// had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
-	mod_timer(&gator_buffer_wake_up_timer, jiffies + 1);
+	if (per_cpu(in_scheduler_context, cpu)) {
+#ifndef CONFIG_PREEMPT_RT_FULL
+		// mod_timer can not be used in interrupt context in RT-Preempt full
+		mod_timer(&gator_buffer_wake_up_timer, jiffies + 1);
+#endif
+	} else {
+		wake_up_process(gator_buffer_wake_thread);
+	}
 }
 
 static void buffer_check(int cpu, int buftype, u64 time)
@@ -590,8 +649,13 @@
 
 	// Collect counters
 	if (!per_cpu(collecting, cpu)) {
-		collect_counters(time);
+		collect_counters(time, NULL);
 	}
+
+	// No buffer flushing occurs during sched switch for RT-Preempt full. The block counter frame will be flushed by collect_counters, but the sched buffer needs to be explicitly flushed
+#ifdef CONFIG_PREEMPT_RT_FULL
+	buffer_check(cpu, SCHED_TRACE_BUF, time);
+#endif
 }
 
 static int gator_running;
@@ -815,6 +879,7 @@
 static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void *dummy)
 {
 	int cpu;
+	struct timespec ts;
 
 	switch (event) {
 	case PM_HIBERNATION_PREPARE:
@@ -825,9 +890,20 @@
 		for_each_online_cpu(cpu) {
 			gator_timer_offline_dispatch(lcpu_to_pcpu(cpu), false);
 		}
+
+		// Record the wallclock hibernate time
+		getnstimeofday(&ts);
+		gator_hibernate_time = timespec_to_ns(&ts) - gator_get_time();
 		break;
 	case PM_POST_HIBERNATION:
 	case PM_POST_SUSPEND:
+		// Adjust gator_monotonic_started for the time spent sleeping, as gator_get_time does not account for it
+		if (gator_hibernate_time > 0) {
+			getnstimeofday(&ts);
+			gator_monotonic_started += gator_hibernate_time + gator_get_time() - timespec_to_ns(&ts);
+			gator_hibernate_time = 0;
+		}
+
 		for_each_online_cpu(cpu) {
 			gator_timer_online_dispatch(lcpu_to_pcpu(cpu), false);
 		}
@@ -902,8 +978,10 @@
 
 int gator_events_get_key(void)
 {
-	// key of zero is reserved as a timestamp
-	static int key = 1;
+	// key 0 is reserved as a timestamp
+	// key 1 is reserved as the marker for thread specific counters
+	// Odd keys are assigned by the driver, even keys by the daemon
+	static int key = 3;
 
 	const int ret = key;
 	key += 2;
@@ -916,7 +994,7 @@
 
 	calc_first_cluster_size();
 
-	// events sources (gator_events.h, generated by gator_events.sh)
+	// events sources
 	for (i = 0; i < ARRAY_SIZE(gator_events_list); i++)
 		if (gator_events_list[i])
 			gator_events_list[i]();
@@ -941,6 +1019,11 @@
 	unsigned long cpu, i;
 	struct gator_interface *gi;
 
+	gator_buffer_wake_stop = false;
+	if (IS_ERR(gator_buffer_wake_thread = kthread_run(gator_buffer_wake_func, NULL, "gator_bwake"))) {
+		goto bwake_failure;
+	}
+
 	if (gator_migrate_start())
 		goto migrate_failure;
 
@@ -1011,6 +1094,9 @@
 events_failure:
 	gator_migrate_stop();
 migrate_failure:
+	gator_buffer_wake_stop = true;
+	wake_up_process(gator_buffer_wake_thread);
+bwake_failure:
 
 	return -1;
 }
@@ -1034,6 +1120,9 @@
 			gi->stop();
 
 	gator_migrate_stop();
+
+	gator_buffer_wake_stop = true;
+	wake_up_process(gator_buffer_wake_thread);
 }
 
 /******************************************************************************
@@ -1438,3 +1527,6 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("ARM Ltd");
 MODULE_DESCRIPTION("Gator system profiler");
+#define STRIFY2(ARG) #ARG
+#define STRIFY(ARG) STRIFY2(ARG)
+MODULE_VERSION(STRIFY(PROTOCOL_VERSION));
diff --git a/drivers/gator/gator_marshaling.c b/drivers/gator/gator_marshaling.c
index 3282de8..af80ff6 100644
--- a/drivers/gator/gator_marshaling.c
+++ b/drivers/gator/gator_marshaling.c
@@ -89,6 +89,25 @@
 	local_irq_restore(flags);
 }
 
+static void marshal_link(int cookie, int tgid, int pid)
+{
+	unsigned long cpu = get_physical_cpu(), flags;
+	u64 time;
+
+	local_irq_save(flags);
+	time = gator_get_time();
+	if (buffer_check_space(cpu, NAME_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) {
+		gator_buffer_write_packed_int(cpu, NAME_BUF, MESSAGE_LINK);
+		gator_buffer_write_packed_int64(cpu, NAME_BUF, time);
+		gator_buffer_write_packed_int(cpu, NAME_BUF, cookie);
+		gator_buffer_write_packed_int(cpu, NAME_BUF, tgid);
+		gator_buffer_write_packed_int(cpu, NAME_BUF, pid);
+	}
+	// Check and commit; commit is set to occur once buffer is 3/4 full
+	buffer_check(cpu, NAME_BUF, time);
+	local_irq_restore(flags);
+}
+
 static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, int inKernel, u64 time)
 {
 	int cpu = get_physical_cpu();
diff --git a/drivers/gator/gator_trace_gpu.c b/drivers/gator/gator_trace_gpu.c
index 12623c4..be135b4 100644
--- a/drivers/gator/gator_trace_gpu.c
+++ b/drivers/gator/gator_trace_gpu.c
@@ -85,7 +85,7 @@
 	int count;
 	int last_tgid = 0;
 	int last_pid = 0;
-	int last_job_id = 0;
+	//int last_job_id = 0;
 
 	spin_lock(&mali_gpu_jobs_lock);
 	if (mali_gpu_jobs[unit][core].count == 0) {
@@ -97,7 +97,7 @@
 	if (count) {
 		last_tgid = mali_gpu_jobs[unit][core].last_tgid;
 		last_pid = mali_gpu_jobs[unit][core].last_pid;
-		last_job_id = mali_gpu_jobs[unit][core].last_job_id;
+		//last_job_id = mali_gpu_jobs[unit][core].last_job_id;
 	}
 	spin_unlock(&mali_gpu_jobs_lock);
 
@@ -242,7 +242,7 @@
 	 * Absence of gpu trace points is not an error
 	 */
 
-	memset(&mali_gpu_jobs, sizeof(mali_gpu_jobs), 0);
+	memset(&mali_gpu_jobs, 0, sizeof(mali_gpu_jobs));
 	gpu_trace_registered = mali_timeline_trace_registered = mali_job_slots_trace_registered = 0;
 
 #if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx)
diff --git a/drivers/gator/gator_trace_sched.c b/drivers/gator/gator_trace_sched.c
index e98815e..332b3f6 100644
--- a/drivers/gator/gator_trace_sched.c
+++ b/drivers/gator/gator_trace_sched.c
@@ -22,6 +22,7 @@
 
 static DEFINE_PER_CPU(uint64_t *, taskname_keys);
 static DEFINE_PER_CPU(int, collecting);
+static DEFINE_PER_CPU(bool, in_scheduler_context);
 
 // this array is never read as the cpu wait charts are derived counters
 // the files are needed, nonetheless, to show that these counters are available
@@ -89,7 +90,7 @@
 	}
 }
 
-static void collect_counters(u64 time)
+static void collect_counters(u64 time, struct task_struct *task)
 {
 	int *buffer, len, cpu = get_physical_cpu();
 	long long *buffer64;
@@ -104,17 +105,26 @@
 				len = gi->read64(&buffer64);
 				marshal_event64(len, buffer64);
 			}
+			if (gi->read_proc && task != NULL) {
+				len = gi->read_proc(&buffer64, task);
+				marshal_event64(len, buffer64);
+			}
 		}
 		// Only check after writing all counters so that time and corresponding counters appear in the same frame
 		buffer_check(cpu, BLOCK_COUNTER_BUF, time);
 
 		// Commit buffers on timeout
 		if (gator_live_rate > 0 && time >= per_cpu(gator_buffer_commit_time, cpu)) {
-			static const int buftypes[] = { COUNTER_BUF, BLOCK_COUNTER_BUF, SCHED_TRACE_BUF };
+			static const int buftypes[] = { NAME_BUF, COUNTER_BUF, BLOCK_COUNTER_BUF, SCHED_TRACE_BUF };
+			unsigned long flags;
 			int i;
+
+			local_irq_save(flags);
 			for (i = 0; i < ARRAY_SIZE(buftypes); ++i) {
 				gator_commit_buffer(cpu, buftypes[i], time);
 			}
+			local_irq_restore(flags);
+
 			// Try to preemptively flush the annotate buffer to reduce the chance of the buffer being full
 			if (on_primary_core() && spin_trylock(&annotate_lock)) {
 				gator_commit_buffer(0, ANNOTATE_BUF, time);
@@ -151,6 +161,8 @@
 	int state;
 	int cpu = get_physical_cpu();
 
+	per_cpu(in_scheduler_context, cpu) = true;
+
 	// do as much work as possible before disabling interrupts
 	cookie = get_exec_cookie(cpu, next);
 	emit_pid_name(next);
@@ -163,10 +175,12 @@
 	}
 
 	per_cpu(collecting, cpu) = 1;
-	collect_counters(gator_get_time());
+	collect_counters(gator_get_time(), prev);
 	per_cpu(collecting, cpu) = 0;
 
 	marshal_sched_trace_switch(next->tgid, next->pid, cookie, state);
+
+	per_cpu(in_scheduler_context, cpu) = false;
 }
 
 GATOR_DEFINE_PROBE(sched_process_free, TP_PROTO(struct task_struct *p))
diff --git a/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h b/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h
index 3db4543..347a4fe 100644
--- a/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h
+++ b/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h
@@ -1,11 +1,10 @@
-/*
- * This confidential and proprietary software may be used only as
- * authorised by a licensing agreement from ARM Limited
- * (C) COPYRIGHT 2013 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.
+/**
+ * Copyright (C) ARM Limited 2013. 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.
+ *
  */
 
 #ifndef __MALI_MJOLLNIR_PROFILING_GATOR_API_H__
diff --git a/drivers/gator/mali/mali_utgard_profiling_gator_api.h b/drivers/gator/mali/mali_utgard_profiling_gator_api.h
index c02a1a4..559647a 100644
--- a/drivers/gator/mali/mali_utgard_profiling_gator_api.h
+++ b/drivers/gator/mali/mali_utgard_profiling_gator_api.h
@@ -1,11 +1,10 @@
-/*
- * This confidential and proprietary software may be used only as
- * authorised by a licensing agreement from ARM Limited
- * (C) COPYRIGHT 2013 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.
+/**
+ * Copyright (C) ARM Limited 2013. 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.
+ *
  */
 
 #ifndef __MALI_UTGARD_PROFILING_GATOR_API_H__
diff --git a/drivers/gator/mali_t6xx.mk b/drivers/gator/mali_t6xx.mk
index 2cc6411..1a98c1c 100644
--- a/drivers/gator/mali_t6xx.mk
+++ b/drivers/gator/mali_t6xx.mk
@@ -9,16 +9,17 @@
                 -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/include/linux
+DDK_DIR ?= .
+KBASE_DIR = $(DDK_DIR)/drivers/gpu/arm/t6xx/kbase
+OSK_DIR = $(DDK_DIR)/drivers/gpu/arm/t6xx/kbase/osk
+UMP_DIR = $(DDK_DIR)/include/linux
 
 # Include directories in the DDK
-EXTRA_CFLAGS += -I$(DDK_DIR) \
+EXTRA_CFLAGS += -I$(KBASE_DIR)/ \
                 -I$(KBASE_DIR)/.. \
                 -I$(OSK_DIR)/.. \
                 -I$(UMP_DIR)/.. \
-                -I$(DDK_DIR)/kernel/include \
+                -I$(DDK_DIR)/include \
                 -I$(KBASE_DIR)/osk/src/linux/include \
                 -I$(KBASE_DIR)/platform_dummy \
                 -I$(KBASE_DIR)/src
diff --git a/tools/gator/daemon/Buffer.cpp b/tools/gator/daemon/Buffer.cpp
index c7abbf3..090a715 100644
--- a/tools/gator/daemon/Buffer.cpp
+++ b/tools/gator/daemon/Buffer.cpp
@@ -193,6 +193,17 @@
 	return retval;
 }
 
+bool Buffer::eventTid (const int tid) {
+	bool retval = false;
+	if (checkSpace(2*MAXSIZE_PACK32)) {
+		packInt(1);	// key of 1 indicates a tid
+		packInt(tid);
+		retval = true;
+	}
+
+	return retval;
+}
+
 void Buffer::event (const int32_t key, const int32_t value) {
 	if (checkSpace(2 * MAXSIZE_PACK32)) {
 		packInt(key);
diff --git a/tools/gator/daemon/Buffer.h b/tools/gator/daemon/Buffer.h
index f820cfd..b3c8d78 100644
--- a/tools/gator/daemon/Buffer.h
+++ b/tools/gator/daemon/Buffer.h
@@ -32,6 +32,7 @@
 	void frame ();
 
 	bool eventHeader (uint64_t curr_time);
+	bool eventTid (int tid);
 	void event (int32_t key, int32_t value);
 	void event64 (int64_t key, int64_t value);
 
@@ -56,6 +57,10 @@
 	char *const buf;
 	uint64_t commitTime;
 	sem_t *const readerSem;
+
+	// Intentionally unimplemented
+	Buffer(const Buffer &);
+	Buffer &operator=(const Buffer &);
 };
 
 #endif // BUFFER_H
diff --git a/tools/gator/daemon/Child.cpp b/tools/gator/daemon/Child.cpp
index c054076..9ee2ef8 100644
--- a/tools/gator/daemon/Child.cpp
+++ b/tools/gator/daemon/Child.cpp
@@ -86,7 +86,7 @@
 	}
 }
 
-static void* durationThread(void* pVoid) {
+static void *durationThread(void *) {
 	prctl(PR_SET_NAME, (unsigned long)&"gatord-duration", 0, 0, 0);
 	sem_wait(&startProfile);
 	if (gSessionData->mSessionIsActive) {
@@ -102,7 +102,7 @@
 	return 0;
 }
 
-static void* stopThread(void* pVoid) {
+static void *stopThread(void *) {
 	OlySocket* socket = child->socket;
 
 	prctl(PR_SET_NAME, (unsigned long)&"gatord-stopper", 0, 0, 0);
@@ -139,7 +139,7 @@
 	return 0;
 }
 
-void* countersThread(void* pVoid) {
+static void *countersThread(void *) {
 	prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0);
 
 	gSessionData->hwmon.start();
@@ -192,7 +192,7 @@
 	return NULL;
 }
 
-static void* senderThread(void* pVoid) {
+static void *senderThread(void *) {
 	int length = 1;
 	char* data;
 	char end_sequence[] = {RESPONSE_APC_DATA, 0, 0, 0, 0};
@@ -340,7 +340,8 @@
 		thread_creation_success = false;
 	}
 
-	if (gSessionData->hwmon.countersEnabled()) {
+	bool startcountersThread = gSessionData->hwmon.countersEnabled();
+	if (startcountersThread) {
 		if (pthread_create(&countersThreadID, NULL, countersThread, this)) {
 			thread_creation_success = false;
 		}
@@ -378,7 +379,7 @@
 	} while (bytesCollected > 0);
 	logg->logMessage("Exit collect data loop");
 
-	if (gSessionData->hwmon.countersEnabled()) {
+	if (startcountersThread) {
 		pthread_join(countersThreadID, NULL);
 	}
 
diff --git a/tools/gator/daemon/Child.h b/tools/gator/daemon/Child.h
index e39d182..0330e9d7 100644
--- a/tools/gator/daemon/Child.h
+++ b/tools/gator/daemon/Child.h
@@ -26,6 +26,10 @@
 	int mNumConnections;
 
 	void initialization();
+
+	// Intentionally unimplemented
+	Child(const Child &);
+	Child &operator=(const Child &);
 };
 
 #endif 	//__CHILD_H__
diff --git a/tools/gator/daemon/ConfigurationXML.h b/tools/gator/daemon/ConfigurationXML.h
index eba7dc4..5650f48 100644
--- a/tools/gator/daemon/ConfigurationXML.h
+++ b/tools/gator/daemon/ConfigurationXML.h
@@ -29,6 +29,10 @@
 	int parse(const char* xmlFile);
 	int configurationsTag(mxml_node_t *node);
 	void configurationTag(mxml_node_t *node);
+
+	// Intentionally unimplemented
+	ConfigurationXML(const ConfigurationXML &);
+	ConfigurationXML &operator=(const ConfigurationXML &);
 };
 
 #endif // COUNTERS_H
diff --git a/tools/gator/daemon/Driver.h b/tools/gator/daemon/Driver.h
index dd1dc27..f3a932f 100644
--- a/tools/gator/daemon/Driver.h
+++ b/tools/gator/daemon/Driver.h
@@ -29,7 +29,7 @@
 	// Emits available counters
 	virtual void writeCounters(mxml_node_t *root) const = 0;
 	// Emits possible dynamically generated events/counters
-	virtual void writeEvents(mxml_node_t *root) const {}
+	virtual void writeEvents(mxml_node_t *) const {}
 
 	Driver *getNext() const { return next; }
 
@@ -39,6 +39,10 @@
 private:
 	static Driver *head;
 	Driver *next;
+
+	// Intentionally unimplemented
+	Driver(const Driver &);
+	Driver &operator=(const Driver &);
 };
 
 #endif // DRIVER_H
diff --git a/tools/gator/daemon/Fifo.h b/tools/gator/daemon/Fifo.h
index ada42b9..d25cd68 100644
--- a/tools/gator/daemon/Fifo.h
+++ b/tools/gator/daemon/Fifo.h
@@ -39,6 +39,10 @@
   sem_t* mReaderSem;
   char*	mBuffer;
   bool	mEnd;
+
+  // Intentionally unimplemented
+  Fifo(const Fifo &);
+  Fifo &operator=(const Fifo &);
 };
 
 #endif 	//__FIFO_H__
diff --git a/tools/gator/daemon/Hwmon.cpp b/tools/gator/daemon/Hwmon.cpp
index 0792568..1d7c0da 100644
--- a/tools/gator/daemon/Hwmon.cpp
+++ b/tools/gator/daemon/Hwmon.cpp
@@ -63,6 +63,10 @@
 	double previous_value;
 
 	sensors_subfeature_type input;
+
+	// Intentionally unimplemented
+	HwmonCounter(const HwmonCounter &);
+	HwmonCounter &operator=(const HwmonCounter &);
 };
 
 HwmonCounter::HwmonCounter(HwmonCounter *next, int key, const sensors_chip_name *chip, const sensors_feature *feature) : next(next), key(key), polled(false), readable(false), enabled(false), duplicate(false), chip(chip), feature(feature) {
diff --git a/tools/gator/daemon/Hwmon.h b/tools/gator/daemon/Hwmon.h
index 35981dc..46bb42e 100644
--- a/tools/gator/daemon/Hwmon.h
+++ b/tools/gator/daemon/Hwmon.h
@@ -34,6 +34,10 @@
 	HwmonCounter *findCounter(const Counter &counter) const;
 
 	HwmonCounter *counters;
+
+	// Intentionally unimplemented
+	Hwmon(const Hwmon &);
+	Hwmon &operator=(const Hwmon &);
 };
 
 #endif // HWMON_H
diff --git a/tools/gator/daemon/OlySocket.cpp b/tools/gator/daemon/OlySocket.cpp
index 132510d..ab5c3c2 100644
--- a/tools/gator/daemon/OlySocket.cpp
+++ b/tools/gator/daemon/OlySocket.cpp
@@ -11,6 +11,7 @@
 #include <stdio.h>
 #ifdef WIN32
 #include <Winsock2.h>
+#include <ws2tcpip.h>
 #else
 #include <netinet/in.h>
 #include <sys/socket.h>
@@ -126,11 +127,17 @@
 }
 
 void OlySocket::createServerSocket(int port) {
+  int family = AF_INET6;
+
   // Create socket
-  mFDServer = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+  mFDServer = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
   if (mFDServer < 0) {
-    logg->logError(__FILE__, __LINE__, "Error creating server socket");
-    handleException();
+    family = AF_INET;
+    mFDServer = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (mFDServer < 0) {
+      logg->logError(__FILE__, __LINE__, "Error creating server socket");
+      handleException();
+    }
   }
 
   // Enable address reuse, another solution would be to create the server socket once and only close it when the object exits
@@ -141,11 +148,11 @@
   }
 
   // Create sockaddr_in structure, ensuring non-populated fields are zero
-  struct sockaddr_in sockaddr;
-  memset((void*)&sockaddr, 0, sizeof(struct sockaddr_in));
-  sockaddr.sin_family = AF_INET;
-  sockaddr.sin_port   = htons(port);
-  sockaddr.sin_addr.s_addr = INADDR_ANY;
+  struct sockaddr_in6 sockaddr;
+  memset((void*)&sockaddr, 0, sizeof(sockaddr));
+  sockaddr.sin6_family = family;
+  sockaddr.sin6_port = htons(port);
+  sockaddr.sin6_addr = in6addr_any;
 
   // Bind the socket to an address
   if (bind(mFDServer, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
diff --git a/tools/gator/daemon/Sender.h b/tools/gator/daemon/Sender.h
index 8f23361..b388f03 100644
--- a/tools/gator/daemon/Sender.h
+++ b/tools/gator/daemon/Sender.h
@@ -33,6 +33,10 @@
 	FILE* mDataFile;
 	char* mDataFileName;
 	pthread_mutex_t mSendMutex;
+
+	// Intentionally unimplemented
+	Sender(const Sender &);
+	Sender &operator=(const Sender &);
 };
 
 #endif 	//__SENDER_H__
diff --git a/tools/gator/daemon/SessionData.cpp b/tools/gator/daemon/SessionData.cpp
index 4068d4e..cf84407 100644
--- a/tools/gator/daemon/SessionData.cpp
+++ b/tools/gator/daemon/SessionData.cpp
@@ -44,13 +44,13 @@
 	SessionXML session(xmlString);
 	session.parse();
 
-	// Set session data values
+	// Set session data values - use prime numbers just below the desired value to reduce the chance of events firing at the same time
 	if (strcmp(session.parameters.sample_rate, "high") == 0) {
-		mSampleRate = 10000;
+		mSampleRate = 9973; // 10000
 	} else if (strcmp(session.parameters.sample_rate, "normal") == 0) {
-		mSampleRate = 1000;
+		mSampleRate = 997; // 1000
 	} else if (strcmp(session.parameters.sample_rate, "low") == 0) {
-		mSampleRate = 100;
+		mSampleRate = 97; // 100
 	} else if (strcmp(session.parameters.sample_rate, "none") == 0) {
 		mSampleRate = 0;
 	} else {
@@ -139,7 +139,9 @@
  }
 
 int getEventKey() {
-	// Start one after the gator.ko's value of 1
+	// key 0 is reserved as a timestamp
+	// key 1 is reserved as the marker for thread specific counters
+	// Odd keys are assigned by the driver, even keys by the daemon
 	static int key = 2;
 
 	const int ret = key;
diff --git a/tools/gator/daemon/SessionData.h b/tools/gator/daemon/SessionData.h
index e72fa5d..c834251 100644
--- a/tools/gator/daemon/SessionData.h
+++ b/tools/gator/daemon/SessionData.h
@@ -16,7 +16,7 @@
 
 #define MAX_PERFORMANCE_COUNTERS	50
 
-#define PROTOCOL_VERSION	16
+#define PROTOCOL_VERSION	17
 #define PROTOCOL_DEV		1000	// Differentiates development versions (timestamp) from release versions
 
 struct ImageLinkList {
@@ -62,6 +62,10 @@
 
 private:
 	void readCpuInfo();
+
+	// Intentionally unimplemented
+	SessionData(const SessionData &);
+	SessionData &operator=(const SessionData &);
 };
 
 extern SessionData* gSessionData;
diff --git a/tools/gator/daemon/SessionXML.h b/tools/gator/daemon/SessionXML.h
index c7e3798..0fb03bd 100644
--- a/tools/gator/daemon/SessionXML.h
+++ b/tools/gator/daemon/SessionXML.h
@@ -33,6 +33,10 @@
 	char*  mPath;
 	void sessionTag(mxml_node_t *tree, mxml_node_t *node);
 	void sessionImage(mxml_node_t *node);
+
+	// Intentionally unimplemented
+	SessionXML(const SessionXML &);
+	SessionXML &operator=(const SessionXML &);
 };
 
 #endif // SESSION_XML_H
diff --git a/tools/gator/daemon/StreamlineSetup.h b/tools/gator/daemon/StreamlineSetup.h
index 092d956..d6d9a6e 100644
--- a/tools/gator/daemon/StreamlineSetup.h
+++ b/tools/gator/daemon/StreamlineSetup.h
@@ -38,6 +38,10 @@
 	void sendDefaults();
 	void sendCounters();
 	void writeConfiguration(char* xml);
+
+	// Intentionally unimplemented
+	StreamlineSetup(const StreamlineSetup &);
+	StreamlineSetup &operator=(const StreamlineSetup &);
 };
 
 #endif 	//__STREAMLINE_SETUP_H__
diff --git a/tools/gator/daemon/common.mk b/tools/gator/daemon/common.mk
index ee2415b..031d169 100644
--- a/tools/gator/daemon/common.mk
+++ b/tools/gator/daemon/common.mk
@@ -6,7 +6,7 @@
 # -std=c++0x is the planned new c++ standard
 # -std=c++98 is the 1998 c++ standard
 CFLAGS += -O3 -Wall -fno-exceptions -pthread -MMD -DETCDIR=\"/etc\" -Ilibsensors
-CXXFLAGS += -fno-rtti
+CXXFLAGS += -fno-rtti -Wextra # -Weffc++
 ifeq ($(WERROR),1)
 	CFLAGS += -Werror
 endif
diff --git a/tools/gator/daemon/events-CCI-400.xml b/tools/gator/daemon/events-CCI-400.xml
index 86db208..4fa7711 100644
--- a/tools/gator/daemon/events-CCI-400.xml
+++ b/tools/gator/daemon/events-CCI-400.xml
@@ -17,7 +17,7 @@
     <event event="0x04" option_set="Slave" title="CCI-400" name="Read: cache" description="Read request handshake: cache maintenance operation, CleanInvalid, CleanShared, MakeInvalid"/>
     <event event="0x05" option_set="Slave" title="CCI-400" name="Read: memory barrier" description="Read request handshake: memory barrier"/>
     <event event="0x06" option_set="Slave" title="CCI-400" name="Read: sync barrier" description="Read request handshake: synchronization barrier"/>
-    <event event="0x07" option_set="Slave" title="CCI-400" name="Read: DVM message, no sync" description="Read request handshake: DVM message, no synchronization"/>
+    <event event="0x07" option_set="Slave" title="CCI-400" name="Read: DVM message, no sync" description="Read request handshake: DVM message, not synchronization"/>
     <event event="0x08" option_set="Slave" title="CCI-400" name="Read: DVM message, sync" description="Read request handshake: DVM message, synchronization"/>
     <event event="0x09" option_set="Slave" title="CCI-400" name="Read: stall" description="Read request stall cycle because the transaction tracker is full. Increase SIx_R_MAX to avoid this stall"/>
     <event event="0x0a" option_set="Slave" title="CCI-400" name="Read data last handshake" description="Read data last handshake: data returned from the snoop instead of from downstream"/>
@@ -45,3 +45,63 @@
     <event event="0x19" option_set="Master" title="CCI-400" name="Write stall: barrier hazard" description="Write request stall cycle because of a barrier hazard"/>
     <event event="0x1a" option_set="Master" title="CCI-400" name="Write stall: tracker full" description="Write request stall cycle because the transaction tracker is full. Increase MIx_W_MAX to avoid this stall. See the CoreLink CCI-400 Cache Coherent Interconnect Integration Manual"/>
   </category>
+
+  <counter_set name="cci-400-r1_cnt" count="4"/>
+  <category name="CCI-400" counter_set="cci-400-r1_cnt" per_cpu="no" supports_event_based_sampling="yes">
+    <event counter="cci-400-r1_ccnt" event="0xff" title="CCI-400 Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
+
+    <option_set name="Slave">
+      <option event_delta="0x00" name="S0" description="Slave interface 0"/>
+      <option event_delta="0x20" name="S1" description="Slave interface 1"/>
+      <option event_delta="0x40" name="S2" description="Slave interface 2"/>
+      <option event_delta="0x60" name="S3" description="Slave interface 3"/>
+      <option event_delta="0x80" name="S4" description="Slave interface 4"/>
+    </option_set>
+
+    <event event="0x00" option_set="Slave" title="CCI-400" name="Read: any" description="Read request handshake: any"/>
+    <event event="0x01" option_set="Slave" title="CCI-400" name="Read: transaction" description="Read request handshake: device transaction"/>
+    <event event="0x02" option_set="Slave" title="CCI-400" name="Read: normal" description="Read request handshake: normal, non-shareable or system-shareable, but not barrier or cache maintenance operation"/>
+    <event event="0x03" option_set="Slave" title="CCI-400" name="Read: shareable" description="Read request handshake: inner- or outer-shareable, but not barrier, DVM message or cache maintenance operation"/>
+    <event event="0x04" option_set="Slave" title="CCI-400" name="Read: cache" description="Read request handshake: cache maintenance operation"/>
+    <event event="0x05" option_set="Slave" title="CCI-400" name="Read: memory barrier" description="Read request handshake: memory barrier"/>
+    <event event="0x06" option_set="Slave" title="CCI-400" name="Read: sync barrier" description="Read request handshake: synchronization barrier"/>
+    <event event="0x07" option_set="Slave" title="CCI-400" name="Read: DVM message, no sync" description="Read request handshake: DVM message, not synchronization"/>
+    <event event="0x08" option_set="Slave" title="CCI-400" name="Read: DVM message, sync" description="Read request handshake: DVM message, synchronization"/>
+    <event event="0x09" option_set="Slave" title="CCI-400" name="Read: stall" description="Read request stall cycle because the transaction tracker is full. Increase SIx_R_MAX to avoid this stall"/>
+    <event event="0x0a" option_set="Slave" title="CCI-400" name="Read data last handshake" description="Read data last handshake: data returned from the snoop instead of from downstream"/>
+    <event event="0x0b" option_set="Slave" title="CCI-400" name="Read data stall cycle" description="Read data stall cycle: RVALIDS is HIGH, RREADYS is LOW"/>
+    <event event="0x0c" option_set="Slave" title="CCI-400" name="Write: any" description="Write request handshake: any"/>
+    <event event="0x0d" option_set="Slave" title="CCI-400" name="Write: transaction" description="Write request handshake: device transaction"/>
+    <event event="0x0e" option_set="Slave" title="CCI-400" name="Write: normal" description="Write request handshake: normal, non-shareable, or system-shareable, but not barrier"/>
+    <event event="0x0f" option_set="Slave" title="CCI-400" name="Write: shareable" description="Write request handshake: inner- or outer-shareable, WriteBack or WriteClean"/>
+    <event event="0x10" option_set="Slave" title="CCI-400" name="Write: WriteUnique" description="Write request handshake: WriteUnique"/>
+    <event event="0x11" option_set="Slave" title="CCI-400" name="Write: WriteLineUnique" description="Write request handshake: WriteLineUnique"/>
+    <event event="0x12" option_set="Slave" title="CCI-400" name="Write: Evict" description="Write request handshake: Evict"/>
+    <event event="0x13" option_set="Slave" title="CCI-400" name="Write stall: tracker full" description="Write request stall cycle because the transaction tracker is full. Increase SIx_W_MAX to avoid this stall"/>
+    <event event="0x14" option_set="Slave" title="CCI-400" name="Read stall: slave hazard" description="Read request stall cycle because of a slave interface ID hazard"/>
+
+    <option_set name="Master">
+      <option event_delta="0xa0" name="M0" description="Master interface 0"/>
+      <option event_delta="0xc0" name="M1" description="Master interface 1"/>
+      <option event_delta="0xe0" name="M2" description="Master interface 2"/>
+    </option_set>
+
+    <event event="0x00" option_set="Master" title="CCI-400" name="Retry fetch" description="RETRY of speculative fetch transaction"/>
+    <event event="0x01" option_set="Master" title="CCI-400" name="Read stall: address hazard" description="Stall cycle because of an address hazard. A read or write invalidation is stalled because of an outstanding transaction to an overlapping address"/>
+    <event event="0x02" option_set="Master" title="CCI-400" name="Read stall: ID hazard" description="Read request stall cycle because of a master interface ID hazard"/>
+    <event event="0x03" option_set="Master" title="CCI-400" name="Read stall: tracker full" description="A read request with a QoS value in the high priority group is stalled for a cycle because the read transaction queue is full. Increase MIx_R_MAX to avoid this stall"/>
+    <event event="0x04" option_set="Master" title="CCI-400" name="Read stall: barrier hazard" description="Read request stall cycle because of a barrier hazard"/>
+    <event event="0x05" option_set="Master" title="CCI-400" name="Write stall: barrier hazard" description="Write request stall cycle because of a barrier hazard"/>
+    <event event="0x06" option_set="Master" title="CCI-400" name="Write stall: tracker full" description="A write request is stalled for a cycle because the write transaction tracker is full. Increase MIx_W_MAX to avoid this stall"/>
+    <event event="0x07" option_set="Master" title="CCI-400" name="Read Stall: Low Priority" description="A read request with a QoS value in the low priority group is stalled for a cycle because there are no slots available in the read queue for the low priority group"/>
+    <event event="0x08" option_set="Master" title="CCI-400" name="Read Stall: Medium Priority" description="A read request with a QoS value in the medium priority group is stalled for a cycle because there are no slots available in the read queue for the medium priority group"/>
+    <event event="0x09" option_set="Master" title="CCI-400" name="Read Stall: VN0" description="A read request is stalled for a cycle while it was waiting for a QVN token on VN0"/>
+    <event event="0x0a" option_set="Master" title="CCI-400" name="Read Stall: VN1" description="A read request is stalled for a cycle while it was waiting for a QVN token on VN1"/>
+    <event event="0x0b" option_set="Master" title="CCI-400" name="Read Stall: VN2" description="A read request is stalled for a cycle while it was waiting for a QVN token on VN2"/>
+    <event event="0x0c" option_set="Master" title="CCI-400" name="Read Stall: VN3" description="A read request is stalled for a cycle while it was waiting for a QVN token on VN3"/>
+    <event event="0x0d" option_set="Master" title="CCI-400" name="Write Stall: VN0" description="A write request is stalled for a cycle while it was waiting for a QVN token on VN0"/>
+    <event event="0x0e" option_set="Master" title="CCI-400" name="Write Stall: VN1" description="A write request is stalled for a cycle while it was waiting for a QVN token on VN1"/>
+    <event event="0x0f" option_set="Master" title="CCI-400" name="Write Stall: VN2" description="A write request is stalled for a cycle while it was waiting for a QVN token on VN2"/>
+    <event event="0x10" option_set="Master" title="CCI-400" name="Write Stall: VN" description="A write request is stalled for a cycle while it was waiting for a QVN token on VN"/>
+    <event event="0x11" option_set="Master" title="CCI-400" name="WriteUnique or WriteLineUnique Stall" description="A WriteUnique or WriteLineUnique request is stalled for a cycle because of an address hazard"/>
+  </category>
diff --git a/tools/gator/daemon/events-Linux.xml b/tools/gator/daemon/events-Linux.xml
index 4a30ad6..31a90a1 100644
--- a/tools/gator/daemon/events-Linux.xml
+++ b/tools/gator/daemon/events-Linux.xml
@@ -6,11 +6,11 @@
     <event counter="Linux_net_rx" title="Network" name="Receive" units="B" description="Receive network traffic, including effect from Streamline"/>
     <event counter="Linux_net_tx" title="Network" name="Transmit" units="B" description="Transmit network traffic, including effect from Streamline"/>
     <event counter="Linux_sched_switch" title="Scheduler" name="Switch" per_cpu="yes" description="Context switch events"/>
-    <event counter="Linux_meminfo_memused" title="Memory" name="Used" display="maximum" units="B" average_selection="yes" description="Total used memory size"/>
-    <event counter="Linux_meminfo_memfree" title="Memory" name="Free" display="minimum" units="B" average_selection="yes" description="Available memory size"/>
-    <event counter="Linux_meminfo_bufferram" title="Memory" name="Buffer" display="maximum" units="B" average_selection="yes" description="Memory used by OS disk buffers"/>
-    <event counter="Linux_power_cpu_freq" title="Clock" name="Frequency" per_cpu="yes" display="maximum" units="Hz" series_composition="overlay" average_selection="yes" average_cores="yes" description="Frequency setting of the CPU"/>
-    <event counter="Linux_power_cpu_idle" title="Idle" name="State" per_cpu="yes" display="maximum" average_selection="yes" description="CPU Idle State + 1, set the Sample Rate to None to prevent the hrtimer from interrupting the system"/>
+    <event counter="Linux_meminfo_memused" title="Memory" name="Used" display="maximum" units="B" proc="yes" description="Total used memory size. Note: a process' used memory includes shared memory that may be counted more than once (equivalent to RES from top). Kernel threads are not filterable."/>
+    <event counter="Linux_meminfo_memfree" title="Memory" name="Free" display="minimum" units="B" description="Available memory size"/>
+    <event counter="Linux_meminfo_bufferram" title="Memory" name="Buffer" display="maximum" units="B" description="Memory used by OS disk buffers"/>
+    <event counter="Linux_power_cpu_freq" title="Clock" name="Frequency" per_cpu="yes" display="maximum" units="Hz" series_composition="overlay" average_cores="yes" description="Frequency setting of the CPU"/>
+    <event counter="Linux_power_cpu_idle" title="Idle" name="State" per_cpu="yes" display="maximum" description="CPU Idle State + 1, set the Sample Rate to None to prevent the hrtimer from interrupting the system"/>
     <event counter="Linux_cpu_wait_contention" title="CPU Contention" name="Wait" per_cpu="no" display="average" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" description="Thread waiting on contended resource"/>
     <event counter="Linux_cpu_wait_io" title="CPU I/O" name="Wait" per_cpu="no" display="average" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" description="Thread waiting on I/O resource"/>
   </category>
diff --git a/tools/gator/daemon/events-Mali-T6xx.xml b/tools/gator/daemon/events-Mali-T6xx.xml
index 647e3d5..2465238 100644
--- a/tools/gator/daemon/events-Mali-T6xx.xml
+++ b/tools/gator/daemon/events-Mali-T6xx.xml
@@ -36,3 +36,13 @@
     <event counter="ARM_Mali-T6xx_MMU_PAGE_FAULT_2" title="Mali MMU Page Fault Add. Space" name="Mali MMU Page Fault Add. Space 2" description="Reports the number of newly allocated pages after a MMU page fault in address space 2."/>
     <event counter="ARM_Mali-T6xx_MMU_PAGE_FAULT_3" title="Mali MMU Page Fault Add. Space" name="Mali MMU Page Fault Add. Space 3" description="Reports the number of newly allocated pages after a MMU page fault in address space 3."/>
   </category>
+
+  <counter_set name="ARM_Mali-T6xx_Filmstrip_cnt" count="1"/>
+  <category name="ARM Mali-T6xx Filmstrip" counter_set="ARM_Mali-T6xx_Filmstrip_cnt" per_cpu="no">
+    <option_set name="fs">
+      <option event_delta="0x3c" name="1:60" description="captures every 60th frame"/>
+      <option event_delta="0x1e" name="1:30" description="captures every 30th frame"/>
+      <option event_delta="0xa" name="1:10" description="captures every 10th frame"/>
+    </option_set>
+    <event event="0x0400" option_set="fs" title="ARM Mali-T6xx" name="Filmstrip" description="Scaled framebuffer"/>
+  </category>
diff --git a/tools/gator/daemon/events-Mali-T6xx_hw.xml b/tools/gator/daemon/events-Mali-T6xx_hw.xml
index 8cfe7c3..03566cb 100644
--- a/tools/gator/daemon/events-Mali-T6xx_hw.xml
+++ b/tools/gator/daemon/events-Mali-T6xx_hw.xml
@@ -60,12 +60,15 @@
 
     <event counter="ARM_Mali-T6xx_FRAG_THREADS" title="Mali Core Threads" name="Fragment threads" description="Number of fragment threads started"/>
     <event counter="ARM_Mali-T6xx_FRAG_DUMMY_THREADS" title="Mali Core Threads" name="Dummy fragment threads" description="Number of dummy fragment threads started"/>
-    <event counter="ARM_Mali-T6xx_COMPUTE_THREADS" title="Mali Core Threads" name="Compute threads" description="Number of vertex\compute threads started"/>
     <event counter="ARM_Mali-T6xx_FRAG_QUADS_LZS_TEST" title="Mali Core Threads" name="Frag threads doing late ZS" description="Number of threads doing late ZS test"/>
     <event counter="ARM_Mali-T6xx_FRAG_QUADS_LZS_KILLED" title="Mali Core Threads" name="Frag threads killed late ZS" description="Number of threads killed by late ZS test"/>
     <event counter="ARM_Mali-T6xx_FRAG_THREADS_LZS_TEST" title="Mali Core Threads" name="Frag threads doing late ZS" description="Number of threads doing late ZS test"/>
     <event counter="ARM_Mali-T6xx_FRAG_THREADS_LZS_KILLED" title="Mali Core Threads" name="Frag threads killed late ZS" description="Number of threads killed by late ZS test"/>
 
+    <event counter="ARM_Mali-T6xx_COMPUTE_TASKS" title="Mali Compute Threads" name="Compute tasks" description="Number of compute tasks"/>
+    <event counter="ARM_Mali-T6xx_COMPUTE_THREADS" title="Mali Compute Threads" name="Compute threads started" description="Number of compute threads started"/>
+    <event counter="ARM_Mali-T6xx_COMPUTE_CYCLES_DESC" title="Mali Compute Threads" name="Compute cycles awaiting descriptors" description="Number of compute cycles spent waiting for descriptors"/>
+
     <event counter="ARM_Mali-T6xx_FRAG_PRIMATIVES" title="Mali Fragment Primitives" name="Primitives loaded" description="Number of primitives loaded from tiler"/>
     <event counter="ARM_Mali-T6xx_FRAG_PRIMATIVES_DROPPED" title="Mali Fragment Primitives" name="Primitives dropped" description="Number of primitives dropped because out of tile"/>
     <event counter="ARM_Mali-T6xx_FRAG_PRIMITIVES" title="Mali Fragment Primitives" name="Primitives loaded" description="Number of primitives loaded from tiler"/>
diff --git a/tools/gator/daemon/main.cpp b/tools/gator/daemon/main.cpp
index d1b0913..bfd36b9 100644
--- a/tools/gator/daemon/main.cpp
+++ b/tools/gator/daemon/main.cpp
@@ -93,7 +93,7 @@
 }
 
 // Child exit Signal Handler
-static void child_exit(int signum) {
+static void child_exit(int) {
 	int status;
 	int pid = wait(&status);
 	if (pid != -1) {
@@ -106,13 +106,18 @@
 
 static int udpPort(int port) {
 	int s;
-	struct sockaddr_in sockaddr;
+	struct sockaddr_in6 sockaddr;
 	int on;
+	int family = AF_INET6;
 
-	s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
 	if (s == -1) {
-		logg->logError(__FILE__, __LINE__, "socket failed");
-		handleException();
+		family = AF_INET;
+		s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+		if (s == -1) {
+			logg->logError(__FILE__, __LINE__, "socket failed");
+			handleException();
+		}
 	}
 
 	on = 1;
@@ -122,9 +127,9 @@
 	}
 
 	memset((void*)&sockaddr, 0, sizeof(sockaddr));
-	sockaddr.sin_family = AF_INET;
-	sockaddr.sin_port = htons(port);
-	sockaddr.sin_addr.s_addr = INADDR_ANY;
+	sockaddr.sin6_family = family;
+	sockaddr.sin6_port = htons(port);
+	sockaddr.sin6_addr = in6addr_any;
 	if (bind(s, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) {
 		logg->logError(__FILE__, __LINE__, "socket failed");
 		handleException();
@@ -173,7 +178,7 @@
 
 	for (;;) {
 		char buf[128];
-		struct sockaddr_in sockaddr;
+		struct sockaddr_in6 sockaddr;
 		socklen_t addrlen;
 		int read;
 		addrlen = sizeof(sockaddr);
@@ -386,7 +391,7 @@
 }
 
 // Gator data flow: collector -> collector fifo -> sender
-int main(int argc, char** argv, char* envp[]) {
+int main(int argc, char** argv) {
 	// Ensure proper signal handling by making gatord the process group leader
 	//   e.g. it may not be the group leader when launched as 'sudo gatord'
 	setsid();