gator: ARM DS-5.6 Streamline gator driver
authorPawel Moll <pawel.moll@arm.com>
Wed, 3 Aug 2011 10:30:26 +0000 (11:30 +0100)
committerPawel Moll <pawel.moll@arm.com>
Wed, 3 Aug 2011 10:30:26 +0000 (11:30 +0100)
Signed-off-by: Pawel Moll <pawel.moll@arm.com>
17 files changed:
Makefile
gator.h
gator_annotate.c
gator_cookies.c
gator_events.sh [new file with mode: 0644]
gator_events_armv6.c
gator_events_armv7.c
gator_events_block.c
gator_events_irq.c
gator_events_meminfo.c
gator_events_mmaped.c [new file with mode: 0644]
gator_events_net.c
gator_events_pl310.c [new file with mode: 0644]
gator_events_sched.c
gator_events_scorpion.c [new file with mode: 0644]
gator_fs.c
gator_main.c

index 0583ae31459705741d1f5c2ee2e656eb93deb812..b3680e11229cdb764499ede0312857d36b1efb25 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,15 +2,34 @@ ifneq ($(KERNELRELEASE),)
 
 obj-m := gator.o
 
-gator-objs :=  gator_main.o \
-               gator_events_armv6.o \
-               gator_events_armv7.o \
+gator-y :=     gator_main.o \
                gator_events_irq.o \
                gator_events_sched.o \
                gator_events_net.o \
                gator_events_block.o \
                gator_events_meminfo.o
 
+gator-y +=     gator_events_mmaped.o
+
+ifneq ($(GATOR_WITH_MALI_SUPPORT),)
+gator-y +=     gator_events_mali.o
+endif
+
+gator-$(CONFIG_ARM) += gator_events_armv6.o \
+                       gator_events_armv7.o \
+                       gator_events_pl310.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:
diff --git a/gator.h b/gator.h
index f0c95bf3e11fc9e6956a210550c85a92fb76f424..9d802a365051d0af6566fa932b81ae8e4f29713b 100644 (file)
--- a/gator.h
+++ b/gator.h
@@ -1,5 +1,5 @@
 /**
- * Copyright 2010  ARM, Ltd.
+ * Copyright (C) ARM Limited 2010-2011. 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
@@ -12,6 +12,7 @@
 #include <linux/version.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
+#include <linux/list.h>
 
 /******************************************************************************
  * Filesystem
@@ -28,6 +29,8 @@ int gatorfs_create_ulong(struct super_block *sb, struct dentry *root,
 int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
        char const *name, unsigned long *val);
 
+void gator_op_create_files(struct super_block *sb, struct dentry *root);
+
 /******************************************************************************
  * Tracepoints
  ******************************************************************************/
@@ -52,21 +55,25 @@ int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
 /******************************************************************************
  * Events
  ******************************************************************************/
-struct __gator_interface {
+struct gator_interface {
        int  (*create_files)(struct super_block *sb, struct dentry *root);
-       int  (*init)(int *key);
        int  (*start)(void);
        void (*stop)(void);
        void (*online)(void);
        void (*offline)(void);
        int  (*read)(int **buffer);
-       struct __gator_interface *next;
+       struct list_head list;
 };
 
-typedef struct __gator_interface gator_interface;
+#define gator_events_init(initfn) \
+       static inline int __gator_events_init_test(void) \
+       { return initfn(); }
 
-int gator_event_install(int (*event_install)(gator_interface *));
+int gator_events_install(struct gator_interface *interface);
+int gator_events_get_key(void);
+extern u32 gator_cpuid(void);
 
 extern unsigned long gator_net_traffic;
 
+
 #endif // GATOR_H_
index f261f736f7b93c0bde989f0df5a909628380842d..d8d86afd10a717d59dfe8afce90123dfd96bda41 100644 (file)
@@ -15,7 +15,7 @@
 #include <asm/current.h>
 #include <linux/spinlock.h>
 
-#define INSTSIZE       1024
+#define ANNOTATE_SIZE  (16*1024)
 static DEFINE_SPINLOCK(annotate_lock);
 static char *annotateBuf;
 static char *annotateBuf0;
@@ -25,35 +25,42 @@ static int annotateSel;
 
 static ssize_t annotate_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
 {
-       char tempBuffer[32];
-       unsigned long flags;
+       char tempBuffer[512];
        int retval, remaining, size;
 
        if (*offset)
                return -EINVAL;
 
        // determine size to capture
-       remaining = INSTSIZE - annotatePos - 24; // leave some extra space
+       remaining = ANNOTATE_SIZE - annotatePos - 256; // pad for headers and release
        size = count < sizeof(tempBuffer) ? count : sizeof(tempBuffer);
        size = size < remaining ? size : remaining;
-       if (size <= 0)
+       if (size <= 0) {
+               wake_up(&gator_buffer_wait);
                return 0;
+       }
 
        // copy from user space
        retval = copy_from_user(tempBuffer, buf, size);
        if (retval == 0) {
                // synchronize shared variables annotateBuf and annotatePos
-               spin_lock_irqsave(&annotate_lock, flags);
-               if (!annotateBuf) {
-                       size = -EINVAL;
-               } else  {
-                       *(int*)&annotateBuf[annotatePos + 0] = current->pid;            // thread id
-                       *(int*)&annotateBuf[annotatePos + 4] = size;                            // length in bytes
-                       memcpy(&annotateBuf[annotatePos + 8], tempBuffer, size);        // data
-                       annotatePos = annotatePos + 8 + size;                                           // increment position
-                       annotatePos = (annotatePos + 3) & ~3;                                           // align to 4-byte boundary
+               spin_lock(&annotate_lock);
+               if (annotateBuf) {
+                       uint32_t tid = current->pid;
+                       uint32_t tick = gator_master_tick;
+                       uint64_t time = gator_get_time();
+                       uint32_t cpuid = smp_processor_id();
+                       int pos = annotatePos;
+                       pos += gator_write_packed_int(&annotateBuf[pos], tid);
+                       pos += gator_write_packed_int(&annotateBuf[pos], tick);
+                       pos += gator_write_packed_int(&annotateBuf[pos], time);
+                       pos += gator_write_packed_int(&annotateBuf[pos], time >> 32);
+                       pos += gator_write_packed_int(&annotateBuf[pos], cpuid);
+                       pos += gator_write_packed_int(&annotateBuf[pos], size);
+                       memcpy(&annotateBuf[pos], tempBuffer, size);
+                       annotatePos = pos + size;
                }
-               spin_unlock_irqrestore(&annotate_lock, flags);
+               spin_unlock(&annotate_lock);
 
                // return the number of bytes written
                retval = size;
@@ -64,64 +71,96 @@ static ssize_t annotate_write(struct file *file, char const __user *buf, size_t
        return retval;
 }
 
+static int annotate_release(struct inode *inode, struct file *file)
+{
+       int remaining = ANNOTATE_SIZE - annotatePos;
+       if (remaining < 16) {
+               return -EFAULT;
+       }
+
+       spin_lock(&annotate_lock);
+       if (annotateBuf) {
+               uint32_t tid = current->pid;
+               uint32_t tick = gator_master_tick;
+               int pos = annotatePos;
+               pos += gator_write_packed_int(&annotateBuf[pos], tid);
+               pos += gator_write_packed_int(&annotateBuf[pos], tick);
+               pos += gator_write_packed_int(&annotateBuf[pos], 0); // time
+               pos += gator_write_packed_int(&annotateBuf[pos], 0); // time
+               pos += gator_write_packed_int(&annotateBuf[pos], 0); // cpuid
+               pos += gator_write_packed_int(&annotateBuf[pos], 0); // size
+               annotatePos = pos;
+       }
+       spin_unlock(&annotate_lock);
+
+       return 0;
+}
+
 static const struct file_operations annotate_fops = {
-       .write          = annotate_write
+       .write          = annotate_write,
+       .release        = annotate_release
 };
 
-int gator_annotate_create_files(struct super_block *sb, struct dentry *root)
+static int gator_annotate_create_files(struct super_block *sb, struct dentry *root)
 {
-       annotateBuf = annotateBuf0 = annotateBuf1 = NULL;
+       annotateBuf = NULL;
        return gatorfs_create_file_perm(sb, root, "annotate", &annotate_fops, 0666);
 }
 
-int gator_annotate_init(void)
+static int gator_annotate_init(void)
 {
+       annotateBuf0 = kmalloc(ANNOTATE_SIZE, GFP_KERNEL);
+       annotateBuf1 = kmalloc(ANNOTATE_SIZE, GFP_KERNEL);
+       if (!annotateBuf0 || !annotateBuf1)
+               return -1;
        return 0;
 }
 
-int gator_annotate_start(void)
+static int gator_annotate_start(void)
 {
        annotatePos = annotateSel = 0;
-       annotateBuf0 = kmalloc(INSTSIZE, GFP_KERNEL);
-       annotateBuf1 = kmalloc(INSTSIZE, GFP_KERNEL);
        annotateBuf = annotateBuf0;
-       if (!annotateBuf0 || !annotateBuf1)
-               return -1;
        return 0;
 }
 
-void gator_annotate_stop(void)
+static void gator_annotate_stop(void)
 {
-       unsigned long flags;
-       spin_lock_irqsave(&annotate_lock, flags);
+       spin_lock(&annotate_lock);
+       annotateBuf = NULL;
+       spin_unlock(&annotate_lock);
+}
 
+static void gator_annotate_exit(void)
+{
+       spin_lock(&annotate_lock);
        kfree(annotateBuf0);
        kfree(annotateBuf1);
        annotateBuf = annotateBuf0 = annotateBuf1 = NULL;
+       spin_unlock(&annotate_lock);
+}
 
-       spin_unlock_irqrestore(&annotate_lock, flags);
+static int gator_annotate_ready(void)
+{
+       return annotatePos && annotateBuf;
 }
 
-int gator_annotate_read(int **buffer)
+static int gator_annotate_read(char **buffer)
 {
        int len;
 
-       if (smp_processor_id() || !annotatePos || !annotateBuf)
+       if (!gator_annotate_ready())
                return 0;
 
        annotateSel = !annotateSel;
 
        if (buffer)
-               *buffer = (int *)annotateBuf;
+               *buffer = annotateBuf;
 
        spin_lock(&annotate_lock);
-
        len = annotatePos;
        annotatePos = 0;
        annotateBuf = annotateSel ? annotateBuf1 : annotateBuf0;
-
        spin_unlock(&annotate_lock);
 
-       // Return number of 4-byte words
-       return len / 4;
+       return len;
 }
index 70fece0df5b1f5e8cb4c3dcf45825e62ddb7ee63..64be84130ac9a48a0d4201932fb1072ac6ab68d1 100644 (file)
@@ -57,7 +57,7 @@ static uint32_t gator_chksum_crc32(char *data)
  */
 static uint32_t cookiemap_exists(uint64_t key) {
        unsigned long x, flags, retval = 0;
-       int cpu = raw_smp_processor_id();
+       int cpu = smp_processor_id();
        uint32_t cookiecode = cookiemap_code(key);
        uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]);
        uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]);
@@ -88,7 +88,7 @@ static uint32_t cookiemap_exists(uint64_t key) {
  *  Post: [v][0][1][2]..[n-2]
  */
 static void cookiemap_add(uint64_t key, uint32_t value) {
-       int cpu = raw_smp_processor_id();
+       int cpu = smp_processor_id();
        int cookiecode = cookiemap_code(key);
        uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]);
        uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]);
diff --git a/gator_events.sh b/gator_events.sh
new file mode 100644 (file)
index 0000000..5467dd6
--- /dev/null
@@ -0,0 +1,19 @@
+#!/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
index c571e44b23183eb34b944168db4e911de28d6dc3..7b1d875084f744fb8ed72f034e4c412969556fd9 100644 (file)
@@ -8,16 +8,12 @@
 
 #include "gator.h"
 
-#if defined(__arm__)
-
 #define ARM1136                0xb36
 #define ARM1156                0xb56
 #define ARM1176                0xb76
 
 static const char *pmnc_name;
 
-extern u32 gator_cpuid(void);
-
 /*
  * Per-CPU PMCR
  */
@@ -99,20 +95,6 @@ int gator_events_armv6_create_files(struct super_block *sb, struct dentry *root)
        return 0;
 }
 
-static int gator_events_armv6_init(int *key)
-{
-       unsigned int cnt;
-
-       for (cnt = PMN0; cnt <= CCNT; cnt++) {
-               pmnc_enabled[cnt] = 0;
-               pmnc_event[cnt] = 0;
-               pmnc_key[cnt] = *key;
-               *key = *key + 1;
-       }
-
-       return 0;
-}
-
 static void gator_events_armv6_online(void)
 {
        unsigned int cnt;
@@ -130,7 +112,7 @@ static void gator_events_armv6_online(void)
        for (pmnc = 0, cnt = PMN0; cnt <= CCNT; cnt++) {
                unsigned long event;
 
-               per_cpu(perfPrev, raw_smp_processor_id())[cnt] = 0;
+               per_cpu(perfPrev, smp_processor_id())[cnt] = 0;
 
                if (!pmnc_enabled[cnt])
                        continue;
@@ -177,7 +159,7 @@ static void gator_events_armv6_stop(void)
 static int gator_events_armv6_read(int **buffer)
 {
        int cnt, len = 0;
-       int cpu = raw_smp_processor_id();
+       int cpu = smp_processor_id();
 
        for (cnt = PMN0; cnt <= CCNT; cnt++) {
                if (pmnc_enabled[cnt]) {
@@ -208,10 +190,19 @@ static int gator_events_armv6_read(int **buffer)
 
        return len;
 }
-#endif
 
-int gator_events_armv6_install(gator_interface *gi) {
-#if defined(__arm__)
+static struct gator_interface gator_events_armv6_interface = {
+       .create_files = gator_events_armv6_create_files,
+       .stop = gator_events_armv6_stop,
+       .online = gator_events_armv6_online,
+       .offline = gator_events_armv6_offline,
+       .read = gator_events_armv6_read,
+};
+
+int gator_events_armv6_init(void)
+{
+       unsigned int cnt;
+
        switch (gator_cpuid()) {
        case ARM1136:
        case ARM1156:
@@ -222,12 +213,12 @@ int gator_events_armv6_install(gator_interface *gi) {
                return -1;
        }
 
-       gi->create_files = gator_events_armv6_create_files;
-       gi->init = gator_events_armv6_init;
-       gi->stop = gator_events_armv6_stop;
-       gi->online = gator_events_armv6_online;
-       gi->offline = gator_events_armv6_offline;
-       gi->read = gator_events_armv6_read;
-#endif
-       return 0;
+       for (cnt = PMN0; cnt <= CCNT; cnt++) {
+               pmnc_enabled[cnt] = 0;
+               pmnc_event[cnt] = 0;
+               pmnc_key[cnt] = gator_events_get_key();
+       }
+
+       return gator_events_install(&gator_events_armv6_interface);
 }
+gator_events_init(gator_events_armv6_init);
index 5a3268fb0e994353628920bcca4582c1ccdcb041..0b8474541b2a101ea72eadd95c6136859573dc15 100644 (file)
@@ -8,76 +8,22 @@
 
 #include "gator.h"
 
-#if defined(__arm__)
-
+#define CORTEX_A5      0xc05
 #define CORTEX_A8      0xc08
 #define CORTEX_A9      0xc09
+#define CORTEX_A15     0xc0f
 
 static const char *pmnc_name;
 static int pmnc_count;
 
-extern u32 gator_cpuid(void);
-
-/*
- * Per-CPU PMNC: config reg
- */
+// Per-CPU PMNC: config reg
 #define PMNC_E         (1 << 0)        /* Enable all counters */
 #define PMNC_P         (1 << 1)        /* Reset all counters */
 #define PMNC_C         (1 << 2)        /* Cycle counter reset */
-#define PMNC_D         (1 << 3)        /* CCNT counts every 64th cpu cycle */
-#define PMNC_X         (1 << 4)        /* Export to ETM */
-#define PMNC_DP                (1 << 5)        /* Disable CCNT if non-invasive debug*/
 #define        PMNC_MASK       0x3f            /* Mask for writable bits */
 
-/*
- * CNTENS: counters enable reg
- */
-#define CNTENS_P0      (1 << 0)
-#define CNTENS_P1      (1 << 1)
-#define CNTENS_P2      (1 << 2)
-#define CNTENS_P3      (1 << 3)
-#define CNTENS_C       (1 << 31)
-#define        CNTENS_MASK     0x8000000f      /* Mask for writable bits */
-
-/*
- * CNTENC: counters disable reg
- */
-#define CNTENC_P0      (1 << 0)
-#define CNTENC_P1      (1 << 1)
-#define CNTENC_P2      (1 << 2)
-#define CNTENC_P3      (1 << 3)
-#define CNTENC_C       (1 << 31)
-#define        CNTENC_MASK     0x8000000f      /* Mask for writable bits */
-
-/*
- * INTENS: counters overflow interrupt enable reg
- */
-#define INTENS_P0      (1 << 0)
-#define INTENS_P1      (1 << 1)
-#define INTENS_P2      (1 << 2)
-#define INTENS_P3      (1 << 3)
-#define INTENS_C       (1 << 31)
-#define        INTENS_MASK     0x8000000f      /* Mask for writable bits */
-
-/*
- * EVTSEL: Event selection reg
- */
-#define        EVTSEL_MASK     0x7f            /* Mask for writable bits */
-
-/*
- * SELECT: Counter selection reg
- */
-#define        SELECT_MASK     0x1f            /* Mask for writable bits */
-
-/*
- * FLAG: counters overflow flag status reg
- */
-#define FLAG_P0                (1 << 0)
-#define FLAG_P1                (1 << 1)
-#define FLAG_P2                (1 << 2)
-#define FLAG_P3                (1 << 3)
-#define FLAG_C         (1 << 31)
-#define        FLAG_MASK       0x8000000f      /* Mask for writable bits */
+// ccnt reg
+#define CCNT_REG       (1 << 31)
 
 #define CCNT           0
 #define CNT0           1
@@ -105,15 +51,31 @@ static inline u32 armv7_pmnc_read(void)
 
 static inline u32 armv7_ccnt_read(void)
 {
+       u32 zero = 0;
+       u32 den = CCNT_REG;
        u32 val;
-       asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));
+
+       asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den));       // disable
+       asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));        // read
+       asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (zero));      // zero
+       asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den));       // enable
+
        return val;
 }
 
-static inline u32 armv7_cntn_read(void)
+static inline u32 armv7_cntn_read(unsigned int cnt)
 {
+       u32 zero = 0;
+       u32 sel = (cnt - CNT0);
+       u32 den = 1 << sel;
        u32 val;
-       asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val));
+
+       asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den));       // disable
+       asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (sel));       // select
+       asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val));        // read
+       asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (zero));      // zero
+       asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den));       // enable
+
        return val;
 }
 
@@ -127,11 +89,10 @@ static inline u32 armv7_pmnc_enable_counter(unsigned int cnt)
        }
 
        if (cnt == CCNT)
-               val = CNTENS_C;
+               val = CCNT_REG;
        else
                val = (1 << (cnt - CNT0));
 
-       val &= CNTENS_MASK;
        asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
 
        return cnt;
@@ -147,50 +108,15 @@ static inline u32 armv7_pmnc_disable_counter(unsigned int cnt)
        }
 
        if (cnt == CCNT)
-               val = CNTENC_C;
+               val = CCNT_REG;
        else
                val = (1 << (cnt - CNT0));
 
-       val &= CNTENC_MASK;
        asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
 
        return cnt;
 }
 
-static inline u32 armv7_pmnc_enable_intens(unsigned int cnt)
-{
-       u32 val;
-
-       if (cnt >= CNTMAX) {
-               pr_err("gator: CPU%u enabling wrong PMNC counter interrupt enable %d\n", smp_processor_id(), cnt);
-               return -1;
-       }
-
-       if (cnt == CCNT)
-               val = INTENS_C;
-       else
-               val = (1 << (cnt - CNT0));
-
-       val &= INTENS_MASK;
-       asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (val));
-
-       return cnt;
-}
-
-static inline u32 armv7_pmnc_getreset_flags(void)
-{
-       u32 val;
-
-       /* Read */
-       asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val));
-
-       /* Write to clear flags */
-       val &= FLAG_MASK;
-       asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (val));
-
-       return val;
-}
-
 static inline int armv7_pmnc_select_counter(unsigned int cnt)
 {
        u32 val;
@@ -200,7 +126,7 @@ static inline int armv7_pmnc_select_counter(unsigned int cnt)
                return -1;
        }
 
-       val = (cnt - CNT0) & SELECT_MASK;
+       val = (cnt - CNT0);
        asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
 
        return cnt;
@@ -209,7 +135,6 @@ static inline int armv7_pmnc_select_counter(unsigned int cnt)
 static inline void armv7_pmnc_write_evtsel(unsigned int cnt, u32 val)
 {
        if (armv7_pmnc_select_counter(cnt) == cnt) {
-               val &= EVTSEL_MASK;
                asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
        }
 }
@@ -265,66 +190,39 @@ static int gator_events_armv7_create_files(struct super_block *sb, struct dentry
        return 0;
 }
 
-static int gator_events_armv7_init(int *key)
-{
-       unsigned int cnt;
-
-       for (cnt = CCNT; cnt < CNTMAX; cnt++) {
-               pmnc_enabled[cnt] = 0;
-               pmnc_event[cnt] = 0;
-               pmnc_key[cnt] = *key;
-               *key = *key + 1;
-       }
-
-       return 0;
-}
-
 static void gator_events_armv7_online(void)
 {
        unsigned int cnt;
+       int cpu = smp_processor_id();
 
        if (armv7_pmnc_read() & PMNC_E) {
                armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E);
        }
 
-       /* Initialize & Reset PMNC: C bit and P bit */
+       // Initialize & Reset PMNC: C bit and P bit
        armv7_pmnc_write(PMNC_P | PMNC_C);
 
        for (cnt = CCNT; cnt < CNTMAX; cnt++) {
                unsigned long event;
 
-               per_cpu(perfPrev, raw_smp_processor_id())[cnt] = 0;
+               per_cpu(perfPrev, cpu)[cnt] = 0;
 
                if (!pmnc_enabled[cnt])
                        continue;
 
-               /*
-                * Disable counter
-                */
+               // Disable counter
                armv7_pmnc_disable_counter(cnt);
 
                event = pmnc_event[cnt] & 255;
 
-               /*
-                * Set event (if destined for PMNx counters)
-                * We don't need to set the event if it's a cycle count
-                */
+               // Set event (if destined for PMNx counters), we don't need to set the event if it's a cycle count
                if (cnt != CCNT)
                        armv7_pmnc_write_evtsel(cnt, event);
 
-               /*
-                * [Do not] Enable interrupt for this counter
-                */
-               /* armv7_pmnc_enable_intens(cnt); */
-
-               /*
-                * Reset counter
-                */
+               // Reset counter
                armv7_pmnc_reset_counter(cnt);
 
-               /*
-                * Enable counter
-                */
+               // Enable counter, but do not enable interrupt for this counter
                armv7_pmnc_enable_counter(cnt);
        }
 
@@ -350,23 +248,19 @@ static void gator_events_armv7_stop(void)
 static int gator_events_armv7_read(int **buffer)
 {
        int cnt, len = 0;
-       int cpu = raw_smp_processor_id();
+       int cpu = smp_processor_id();
 
        if (!pmnc_count)
                return 0;
 
-       armv7_pmnc_getreset_flags();
        for (cnt = 0; cnt < pmnc_count; cnt++) {
                if (pmnc_enabled[cnt]) {
                        int value;
                        if (cnt == CCNT) {
                                value = armv7_ccnt_read();
-                       } else if (armv7_pmnc_select_counter(cnt) == cnt) {
-                               value = armv7_cntn_read();
                        } else {
-                               value = 0;
+                               value = armv7_cntn_read(cnt);
                        }
-                       armv7_pmnc_reset_counter(cnt);
                        if (value != per_cpu(perfPrev, cpu)[cnt]) {
                                per_cpu(perfPrev, cpu)[cnt] = value;
                                per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
@@ -381,11 +275,24 @@ static int gator_events_armv7_read(int **buffer)
 
        return len;
 }
-#endif
 
-int gator_events_armv7_install(gator_interface *gi) {
-#if defined(__arm__)
+static struct gator_interface gator_events_armv7_interface = {
+       .create_files = gator_events_armv7_create_files,
+       .stop = gator_events_armv7_stop,
+       .online = gator_events_armv7_online,
+       .offline = gator_events_armv7_offline,
+       .read = gator_events_armv7_read,
+};
+
+int gator_events_armv7_init(void)
+{
+       unsigned int cnt;
+
        switch (gator_cpuid()) {
+       case CORTEX_A5:
+               pmnc_name = "Cortex-A5";
+               pmnc_count = 2;
+               break;
        case CORTEX_A8:
                pmnc_name = "Cortex-A8";
                pmnc_count = 4;
@@ -394,18 +301,22 @@ int gator_events_armv7_install(gator_interface *gi) {
                pmnc_name = "Cortex-A9";
                pmnc_count = 6;
                break;
+       case CORTEX_A15:
+               pmnc_name = "Cortex-A15";
+               pmnc_count = 6;
+               break;
        default:
                return -1;
        }
 
        pmnc_count++; // CNT[n] + CCNT
 
-       gi->create_files = gator_events_armv7_create_files;
-       gi->init = gator_events_armv7_init;
-       gi->stop = gator_events_armv7_stop;
-       gi->online = gator_events_armv7_online;
-       gi->offline = gator_events_armv7_offline;
-       gi->read = gator_events_armv7_read;
-#endif
-       return 0;
+       for (cnt = CCNT; cnt < CNTMAX; cnt++) {
+               pmnc_enabled[cnt] = 0;
+               pmnc_event[cnt] = 0;
+               pmnc_key[cnt] = gator_events_get_key();
+       }
+
+       return gator_events_install(&gator_events_armv7_interface);
 }
+gator_events_init(gator_events_armv7_init);
index f32d8ef6520b5d000d43a191d4224836834c2807..cbfed862830a4f8e47109adc4929f262173f8061 100644 (file)
@@ -33,7 +33,7 @@ GATOR_DEFINE_PROBE(block_rq_complete, TP_PROTO(struct request_queue *q, struct r
 {
        unsigned long flags;
        int write, size;
-       int cpu = raw_smp_processor_id();
+       int cpu = smp_processor_id();
 
        if (!rq)
                return;
@@ -79,19 +79,6 @@ static int gator_events_block_create_files(struct super_block *sb, struct dentry
        return 0;
 }
 
-static int gator_events_block_init(int *key)
-{
-       block_rq_wr_enabled = 0;
-       block_rq_rd_enabled = 0;
-
-       block_rq_wr_key = *key;
-       *key = *key + 1;
-       block_rq_rd_key = *key;
-       *key = *key + 1;
-
-       return 0;
-}
-
 static int gator_events_block_start(void)
 {
        int cpu;
@@ -128,7 +115,7 @@ static int gator_events_block_read(int **buffer)
 {
        unsigned long flags;
        int len, value, cpu, data = 0;
-       cpu = raw_smp_processor_id();
+       cpu = smp_processor_id();
 
        if (per_cpu(new_data_avail, cpu) == false)
                return 0;
@@ -164,11 +151,21 @@ static int gator_events_block_read(int **buffer)
        return len;
 }
 
-int gator_events_block_install(gator_interface *gi) {
-       gi->create_files = gator_events_block_create_files;
-       gi->init = gator_events_block_init;
-       gi->start = gator_events_block_start;
-       gi->stop = gator_events_block_stop;
-       gi->read = gator_events_block_read;
-       return 0;
+static struct gator_interface gator_events_block_interface = {
+       .create_files = gator_events_block_create_files,
+       .start = gator_events_block_start,
+       .stop = gator_events_block_stop,
+       .read = gator_events_block_read,
+};
+
+int gator_events_block_init(void)
+{
+       block_rq_wr_enabled = 0;
+       block_rq_rd_enabled = 0;
+
+       block_rq_wr_key = gator_events_get_key();
+       block_rq_rd_key = gator_events_get_key();
+
+       return gator_events_install(&gator_events_block_interface);
 }
+gator_events_init(gator_events_block_init);
index 7bbbd4bde9a4cbd160009134b46af3475353e5dd..36a6589635138e0c51513410bef7e2c76797a808 100644 (file)
@@ -30,7 +30,7 @@ GATOR_DEFINE_PROBE(irq_handler_exit, TP_PROTO(int irq,
        // disable interrupts to synchronize with gator_events_irq_read()
        // spinlocks not needed since percpu buffers are used
        local_irq_save(flags);
-       per_cpu(irqCnt, raw_smp_processor_id())[HARDIRQ]++;
+       per_cpu(irqCnt, smp_processor_id())[HARDIRQ]++;
        local_irq_restore(flags);
 }
 
@@ -45,7 +45,7 @@ GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(unsigned int vec_nr))
        // disable interrupts to synchronize with gator_events_irq_read()
        // spinlocks not needed since percpu buffers are used
        local_irq_save(flags);
-       per_cpu(irqCnt, raw_smp_processor_id())[SOFTIRQ]++;
+       per_cpu(irqCnt, smp_processor_id())[SOFTIRQ]++;
        local_irq_restore(flags);
 }
 
@@ -72,19 +72,6 @@ static int gator_events_irq_create_files(struct super_block *sb, struct dentry *
        return 0;
 }
 
-static int gator_events_irq_init(int *key)
-{
-       hardirq_key = *key;
-       *key = *key + 1;
-       softirq_key = *key;
-       *key = *key + 1;
-
-       hardirq_enabled = 0;
-       softirq_enabled = 0;
-
-       return 0;
-}
-
 static int gator_events_irq_start(void)
 {
        int cpu, i;
@@ -131,7 +118,7 @@ static int gator_events_irq_read(int **buffer)
 {
        unsigned long flags;
        int len, value;
-       int cpu = raw_smp_processor_id();
+       int cpu = smp_processor_id();
 
        len = 0;
        if (hardirq_enabled) {
@@ -164,11 +151,21 @@ static int gator_events_irq_read(int **buffer)
        return len;
 }
 
-int gator_events_irq_install(gator_interface *gi) {
-       gi->create_files = gator_events_irq_create_files;
-       gi->init = gator_events_irq_init;
-       gi->start = gator_events_irq_start;
-       gi->stop = gator_events_irq_stop;
-       gi->read = gator_events_irq_read;
-       return 0;
+static struct gator_interface gator_events_irq_interface = {
+       .create_files = gator_events_irq_create_files,
+       .start = gator_events_irq_start,
+       .stop = gator_events_irq_stop,
+       .read = gator_events_irq_read,
+};
+
+int gator_events_irq_init(void)
+{
+       hardirq_key = gator_events_get_key();
+       softirq_key = gator_events_get_key();
+
+       hardirq_enabled = 0;
+       softirq_enabled = 0;
+
+       return gator_events_install(&gator_events_irq_interface);
 }
+gator_events_init(gator_events_irq_init);
index 1b576f89130afb34cad447eb6bf6c725df16be32..f1595bdac2021a8e61e046e19105dd17a56413cf 100644 (file)
@@ -69,20 +69,6 @@ static int gator_events_meminfo_create_files(struct super_block *sb, struct dent
        return 0;
 }
 
-static int gator_events_meminfo_init(int *key)
-{
-       int i;
-
-       meminfo_global_enabled = 0;
-       for (i = 0; i < MEMINFO_TOTAL; i++) {
-               meminfo_enabled[i] = 0;
-               meminfo_key[i] = *key;
-               *key = *key + 1;
-       }
-
-       return 0;
-}
-
 static int gator_events_meminfo_start(void)
 {
        int i;
@@ -187,11 +173,23 @@ static int gator_events_meminfo_read(int **buffer)
        return meminfo_length;
 }
 
-int gator_events_meminfo_install(gator_interface *gi) {
-       gi->create_files = gator_events_meminfo_create_files;
-       gi->init = gator_events_meminfo_init;
-       gi->start = gator_events_meminfo_start;
-       gi->stop = gator_events_meminfo_stop;
-       gi->read = gator_events_meminfo_read;
-       return 0;
+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,
+       .read = gator_events_meminfo_read,
+};
+
+int gator_events_meminfo_init(void)
+{
+       int i;
+
+       meminfo_global_enabled = 0;
+       for (i = 0; i < MEMINFO_TOTAL; i++) {
+               meminfo_enabled[i] = 0;
+               meminfo_key[i] = gator_events_get_key();
+       }
+
+       return gator_events_install(&gator_events_meminfo_interface);
 }
+gator_events_init(gator_events_meminfo_init);
diff --git a/gator_events_mmaped.c b/gator_events_mmaped.c
new file mode 100644 (file)
index 0000000..6884684
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Example events provider
+ *
+ * Copyright (C) ARM Limited 2010-2011. 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 entires must be present in events.xml file:
+ *
+ * <counter_set name="mmaped_cntX">
+ *   <counter name="mmaped_cnt0"/>
+ *   <counter name="mmaped_cnt1"/>
+ * </counter_set>
+ * <category name="mmaped" counter_set="mmaped_cntX" per_cpu="no">
+ *   <event event="0x0" title="Simulated" name="Sine" description="Sort-of-sine"/>
+ *   <event event="0x1" title="Simulated" name="Triangle" description="Triangular wave"/>
+ *   <event event="0x2" title="Simulated" name="PWM" 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
+
+/* 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
+
+       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 result = 0;
+
+       switch (counter) {
+       case 0: /* sort-of-sine */
+               {
+                       static int t;
+                       int x;
+
+                       if (t % 1024 < 512)
+                               x = 512 - (t % 512);
+                       else
+                               x = t % 512;
+
+                       result = 32 * x / 512;
+                       result = result * result;
+
+                       if (t < 1024)
+                               result = 1922 - result;
+
+                       t = (t + 1) % 2048;
+               }
+               break;
+       case 1: /* triangle */
+               {
+                       static int v, d = 1;
+
+                       v += d;
+                       if (v % 2000 == 0)
+                               d = -d;
+
+                       result = v;
+               }
+               break;
+       case 2: /* PWM signal */
+               {
+                       static int t, dc;
+
+                       t = (t + 1) % 2000;
+                       if (t % 100)
+                               dc = (dc + 200) % 2000;
+                       
+                       result = t < dc ? 0 : 2000;
+               }
+               break;
+       }
+
+       return result;
+}
+#endif
+
+static int gator_events_mmaped_read(int **buffer)
+{
+       int i;
+       int len = 0;
+
+       /* System wide counters - read from one core only */
+       if (smp_processor_id())
+               return 0;
+
+       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);
+#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);
index 15a395ee6b6f8ee5f1fe7ab1469dcd69aa3f8dab..a92158648751617113a4dd20cd010b452ec0470f 100644 (file)
@@ -101,22 +101,6 @@ static int gator_events_net_create_files(struct super_block *sb, struct dentry *
        return 0;
 }
 
-static int gator_events_net_init(int *key)
-{
-       netdrv_key = *key;
-       *key = *key + 1;
-       netrx_key = *key;
-       *key = *key + 1;
-       nettx_key = *key;
-       *key = *key + 1;
-
-       netdrv_enabled = 0;
-       netrx_enabled = 0;
-       nettx_enabled = 0;
-
-       return 0;
-}
-
 static int gator_events_net_start(void)
 {
        get_network_stats(NULL);
@@ -138,7 +122,7 @@ static int gator_events_net_read(int **buffer)
        int len, drv_delta, rx_delta, tx_delta;
        static int last_drv_delta = 0, last_rx_delta = 0, last_tx_delta = 0;
 
-       if (raw_smp_processor_id() != 0)
+       if (smp_processor_id() != 0)
                return 0;
 
        schedule_work(&wq_get_stats);
@@ -169,12 +153,25 @@ static int gator_events_net_read(int **buffer)
        return len;
 }
 
-int gator_events_net_install(gator_interface *gi) {
-       gi->create_files = gator_events_net_create_files;
-       gi->init = gator_events_net_init;
-       gi->start = gator_events_net_start;
-       gi->stop = gator_events_net_stop;
-       gi->read = gator_events_net_read;
+static struct gator_interface gator_events_net_interface = {
+       .create_files = gator_events_net_create_files,
+       .start = gator_events_net_start,
+       .stop = gator_events_net_stop,
+       .read = gator_events_net_read,
+};
+
+int gator_events_net_init(void)
+{
        gator_net_traffic++;
-       return 0;
+
+       netdrv_key = gator_events_get_key();
+       netrx_key = gator_events_get_key();
+       nettx_key = gator_events_get_key();
+
+       netdrv_enabled = 0;
+       netrx_enabled = 0;
+       nettx_enabled = 0;
+
+       return gator_events_install(&gator_events_net_interface);
 }
+gator_events_init(gator_events_net_init);
diff --git a/gator_events_pl310.c b/gator_events_pl310.c
new file mode 100644 (file)
index 0000000..0ef0cf3
--- /dev/null
@@ -0,0 +1,176 @@
+/**
+ * PL310 (L2 Cache Controller) event counters for gator
+ *
+ * Copyright (C) ARM Limited 2010-2011. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#include "gator.h"
+
+#define PL310_COUNTERS_NUM 2
+
+static struct {
+       unsigned long enabled;
+       unsigned long event;
+       unsigned long key;
+} pl310_counters[PL310_COUNTERS_NUM];
+
+static int pl310_buffer[PL310_COUNTERS_NUM * 2];
+
+static void __iomem *pl310_base;
+
+
+
+static void gator_events_pl310_reset_counters(void)
+{
+       u32 val = readl(pl310_base + L2X0_EVENT_CNT_CTRL);
+
+       val |= ((1 << PL310_COUNTERS_NUM) - 1) << 1;
+
+       writel(val, pl310_base + L2X0_EVENT_CNT_CTRL);
+}
+
+
+static int gator_events_pl310_create_files(struct super_block *sb,
+               struct dentry *root)
+{
+       int i;
+
+       for (i = 0; i < PL310_COUNTERS_NUM; i++) {
+               char buf[16];
+               struct dentry *dir;
+
+               snprintf(buf, sizeof(buf), "PL310_cnt%d", i);
+               dir = gatorfs_mkdir(sb, root, buf);
+               if (WARN_ON(!dir))
+                       return -1;
+               gatorfs_create_ulong(sb, dir, "enabled",
+                               &pl310_counters[i].enabled);
+               gatorfs_create_ulong(sb, dir, "event",
+                               &pl310_counters[i].event);
+               gatorfs_create_ro_ulong(sb, dir, "key",
+                               &pl310_counters[i].key);
+       }
+
+       return 0;
+}
+
+static int gator_events_pl310_start(void)
+{
+       static const unsigned long l2x0_event_cntx_cfg[PL310_COUNTERS_NUM] = {
+               L2X0_EVENT_CNT0_CFG,
+               L2X0_EVENT_CNT1_CFG,
+       };
+       int i;
+
+       /* Counter event sources */
+       for (i = 0; i < PL310_COUNTERS_NUM; i++)
+               writel((pl310_counters[i].event & 0xf) << 2,
+                               pl310_base + l2x0_event_cntx_cfg[i]);
+
+       gator_events_pl310_reset_counters();
+
+       /* Event counter enable */
+       writel(1, pl310_base + L2X0_EVENT_CNT_CTRL);
+
+       return 0;
+}
+
+static void gator_events_pl310_stop(void)
+{
+       /* Event counter disable */
+       writel(0, pl310_base + L2X0_EVENT_CNT_CTRL);
+}
+
+static int gator_events_pl310_read(int **buffer)
+{
+       static const unsigned long l2x0_event_cntx_val[PL310_COUNTERS_NUM] = {
+               L2X0_EVENT_CNT0_VAL,
+               L2X0_EVENT_CNT1_VAL,
+       };
+       int i;
+       int len = 0;
+
+       if (smp_processor_id())
+               return 0;
+
+       for (i = 0; i < PL310_COUNTERS_NUM; i++) {
+               if (pl310_counters[i].enabled) {
+                       pl310_buffer[len++] = pl310_counters[i].key;
+                       pl310_buffer[len++] = readl(pl310_base +
+                                       l2x0_event_cntx_val[i]);
+               }
+       }
+       
+       /* PL310 counters are saturating, not wrapping in case of overflow */
+       gator_events_pl310_reset_counters();
+
+       if (buffer)
+               *buffer = pl310_buffer;
+
+       return len;
+}
+
+static struct gator_interface gator_events_pl310_interface = {
+       .create_files = gator_events_pl310_create_files,
+       .start = gator_events_pl310_start,
+       .stop = gator_events_pl310_stop,
+       .read = gator_events_pl310_read,
+};
+
+static void __maybe_unused gator_events_pl310_probe(unsigned long phys)
+{
+       if (pl310_base)
+               return;
+
+       pl310_base = ioremap(phys, SZ_4K);
+       if (pl310_base) {
+               u32 cache_id = readl(pl310_base + L2X0_CACHE_ID);
+
+               if ((cache_id & 0xff0003c0) != 0x410000c0) {
+                       iounmap(pl310_base);
+                       pl310_base = NULL;
+               }
+       }
+}
+
+int gator_events_pl310_init(void)
+{
+       int i;
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+       gator_events_pl310_probe(0xfe600000);
+#endif
+#if defined(CONFIG_ARCH_OMAP4)
+       gator_events_pl310_probe(0x48242000);
+#endif
+#if defined(CONFIG_ARCH_TEGRA)
+       gator_events_pl310_probe(0x50043000);
+#endif
+#if defined(CONFIG_ARCH_U8500)
+       gator_events_pl310_probe(0xa0412000);
+#endif
+#if defined(CONFIG_ARCH_VEXPRESS) && !defined(CONFIG_ARCH_VEXPRESS_CA15X4)
+       // A9x4 core tile (HBI-0191)
+       gator_events_pl310_probe(0x1e00a000);
+       // New memory map tiles
+       gator_events_pl310_probe(0x2c0f0000);
+#endif
+       if (!pl310_base)
+               return -1;
+
+       for (i = 0; i < PL310_COUNTERS_NUM; i++) {
+               pl310_counters[i].enabled = 0;
+               pl310_counters[i].key = gator_events_get_key();
+       }
+
+       return gator_events_install(&gator_events_pl310_interface);
+}
+gator_events_init(gator_events_pl310_init);
index 138b7e4a64ce3a20705b2b91a9886e6090b03b99..7e9db6082eac84955b7d490d7cb3fbadf60e1c3d 100644 (file)
@@ -29,7 +29,7 @@ GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_
        // disable interrupts to synchronize with gator_events_sched_read()
        // spinlocks not needed since percpu buffers are used
        local_irq_save(flags);
-       per_cpu(schedCnt, raw_smp_processor_id())[SCHED_SWITCH]++;
+       per_cpu(schedCnt, smp_processor_id())[SCHED_SWITCH]++;
        local_irq_restore(flags);
 }
 
@@ -48,16 +48,6 @@ static int gator_events_sched_create_files(struct super_block *sb, struct dentry
        return 0;
 }
 
-static int gator_events_sched_init(int *key)
-{
-       sched_switch_enabled = 0;
-
-       sched_switch_key = *key;
-       *key = *key + 1;
-
-       return 0;
-}
-
 static int gator_events_sched_start(void)
 {
        // register tracepoints
@@ -88,7 +78,7 @@ static int gator_events_sched_read(int **buffer)
 {
        unsigned long flags;
        int len, value;
-       int cpu = raw_smp_processor_id();
+       int cpu = smp_processor_id();
 
        len = 0;
        if (sched_switch_enabled) {
@@ -106,11 +96,19 @@ static int gator_events_sched_read(int **buffer)
        return len;
 }
 
-int gator_events_sched_install(gator_interface *gi) {
-       gi->create_files = gator_events_sched_create_files;
-       gi->init = gator_events_sched_init;
-       gi->start = gator_events_sched_start;
-       gi->stop = gator_events_sched_stop;
-       gi->read = gator_events_sched_read;
-       return 0;
+static struct gator_interface gator_events_sched_interface = {
+       .create_files = gator_events_sched_create_files,
+       .start = gator_events_sched_start,
+       .stop = gator_events_sched_stop,
+       .read = gator_events_sched_read,
+};
+
+int gator_events_sched_init(void)
+{
+       sched_switch_enabled = 0;
+
+       sched_switch_key = gator_events_get_key();
+
+       return gator_events_install(&gator_events_sched_interface);
 }
+gator_events_init(gator_events_sched_init);
diff --git a/gator_events_scorpion.c b/gator_events_scorpion.c
new file mode 100644 (file)
index 0000000..d831a50
--- /dev/null
@@ -0,0 +1,661 @@
+/**
+ * Copyright (C) ARM Limited 2011. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "gator.h"
+
+#define SCORPION       0xf
+#define SCORPIONMP     0x2d
+
+static const char *pmnc_name;
+static int pmnc_count;
+
+// Per-CPU PMNC: config reg
+#define PMNC_E         (1 << 0)        /* Enable all counters */
+#define PMNC_P         (1 << 1)        /* Reset all counters */
+#define PMNC_C         (1 << 2)        /* Cycle counter reset */
+#define PMNC_D         (1 << 3)        /* CCNT counts every 64th cpu cycle */
+#define PMNC_X         (1 << 4)        /* Export to ETM */
+#define PMNC_DP                (1 << 5)        /* Disable CCNT if non-invasive debug*/
+#define        PMNC_MASK       0x3f            /* Mask for writable bits */
+
+// ccnt reg
+#define CCNT_REG       (1 << 31)
+
+#define CCNT           0
+#define CNT0           1
+#define CNTMAX                 (4+1)
+
+static unsigned long pmnc_enabled[CNTMAX];
+static unsigned long pmnc_event[CNTMAX];
+static unsigned long pmnc_key[CNTMAX];
+
+static DEFINE_PER_CPU(int[CNTMAX], perfPrev);
+static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
+
+enum scorpion_perf_types {
+       SCORPION_ICACHE_EXPL_INV                = 0x4c,
+       SCORPION_ICACHE_MISS                    = 0x4d,
+       SCORPION_ICACHE_ACCESS                  = 0x4e,
+       SCORPION_ICACHE_CACHEREQ_L2             = 0x4f,
+       SCORPION_ICACHE_NOCACHE_L2              = 0x50,
+       SCORPION_HIQUP_NOPED                    = 0x51,
+       SCORPION_DATA_ABORT                     = 0x52,
+       SCORPION_IRQ                            = 0x53,
+       SCORPION_FIQ                            = 0x54,
+       SCORPION_ALL_EXCPT                      = 0x55,
+       SCORPION_UNDEF                          = 0x56,
+       SCORPION_SVC                            = 0x57,
+       SCORPION_SMC                            = 0x58,
+       SCORPION_PREFETCH_ABORT                 = 0x59,
+       SCORPION_INDEX_CHECK                    = 0x5a,
+       SCORPION_NULL_CHECK                     = 0x5b,
+       SCORPION_EXPL_ICIALLU                   = 0x5c,
+       SCORPION_IMPL_ICIALLU                   = 0x5d,
+       SCORPION_NONICIALLU_BTAC_INV            = 0x5e,
+       SCORPION_ICIMVAU_IMPL_ICIALLU           = 0x5f,
+       SCORPION_SPIPE_ONLY_CYCLES              = 0x60,
+       SCORPION_XPIPE_ONLY_CYCLES              = 0x61,
+       SCORPION_DUAL_CYCLES                    = 0x62,
+       SCORPION_DISPATCH_ANY_CYCLES            = 0x63,
+       SCORPION_FIFO_FULLBLK_CMT               = 0x64,
+       SCORPION_FAIL_COND_INST                 = 0x65,
+       SCORPION_PASS_COND_INST                 = 0x66,
+       SCORPION_ALLOW_VU_CLK                   = 0x67,
+       SCORPION_VU_IDLE                        = 0x68,
+       SCORPION_ALLOW_L2_CLK                   = 0x69,
+       SCORPION_L2_IDLE                        = 0x6a,
+       SCORPION_DTLB_IMPL_INV_SCTLR_DACR       = 0x6b,
+       SCORPION_DTLB_EXPL_INV                  = 0x6c,
+       SCORPION_DTLB_MISS                      = 0x6d,
+       SCORPION_DTLB_ACCESS                    = 0x6e,
+       SCORPION_ITLB_MISS                      = 0x6f,
+       SCORPION_ITLB_IMPL_INV                  = 0x70,
+       SCORPION_ITLB_EXPL_INV                  = 0x71,
+       SCORPION_UTLB_D_MISS                    = 0x72,
+       SCORPION_UTLB_D_ACCESS                  = 0x73,
+       SCORPION_UTLB_I_MISS                    = 0x74,
+       SCORPION_UTLB_I_ACCESS                  = 0x75,
+       SCORPION_UTLB_INV_ASID                  = 0x76,
+       SCORPION_UTLB_INV_MVA                   = 0x77,
+       SCORPION_UTLB_INV_ALL                   = 0x78,
+       SCORPION_S2_HOLD_RDQ_UNAVAIL            = 0x79,
+       SCORPION_S2_HOLD                        = 0x7a,
+       SCORPION_S2_HOLD_DEV_OP                 = 0x7b,
+       SCORPION_S2_HOLD_ORDER                  = 0x7c,
+       SCORPION_S2_HOLD_BARRIER                = 0x7d,
+       SCORPION_VIU_DUAL_CYCLE                 = 0x7e,
+       SCORPION_VIU_SINGLE_CYCLE               = 0x7f,
+       SCORPION_VX_PIPE_WAR_STALL_CYCLES       = 0x80,
+       SCORPION_VX_PIPE_WAW_STALL_CYCLES       = 0x81,
+       SCORPION_VX_PIPE_RAW_STALL_CYCLES       = 0x82,
+       SCORPION_VX_PIPE_LOAD_USE_STALL         = 0x83,
+       SCORPION_VS_PIPE_WAR_STALL_CYCLES       = 0x84,
+       SCORPION_VS_PIPE_WAW_STALL_CYCLES       = 0x85,
+       SCORPION_VS_PIPE_RAW_STALL_CYCLES       = 0x86,
+       SCORPION_EXCEPTIONS_INV_OPERATION       = 0x87,
+       SCORPION_EXCEPTIONS_DIV_BY_ZERO         = 0x88,
+       SCORPION_COND_INST_FAIL_VX_PIPE         = 0x89,
+       SCORPION_COND_INST_FAIL_VS_PIPE         = 0x8a,
+       SCORPION_EXCEPTIONS_OVERFLOW            = 0x8b,
+       SCORPION_EXCEPTIONS_UNDERFLOW           = 0x8c,
+       SCORPION_EXCEPTIONS_DENORM              = 0x8d,
+#ifdef CONFIG_ARCH_MSM_SCORPIONMP
+       SCORPIONMP_NUM_BARRIERS                 = 0x8e,
+       SCORPIONMP_BARRIER_CYCLES               = 0x8f,
+#else
+       SCORPION_BANK_AB_HIT                    = 0x8e,
+       SCORPION_BANK_AB_ACCESS                 = 0x8f,
+       SCORPION_BANK_CD_HIT                    = 0x90,
+       SCORPION_BANK_CD_ACCESS                 = 0x91,
+       SCORPION_BANK_AB_DSIDE_HIT              = 0x92,
+       SCORPION_BANK_AB_DSIDE_ACCESS           = 0x93,
+       SCORPION_BANK_CD_DSIDE_HIT              = 0x94,
+       SCORPION_BANK_CD_DSIDE_ACCESS           = 0x95,
+       SCORPION_BANK_AB_ISIDE_HIT              = 0x96,
+       SCORPION_BANK_AB_ISIDE_ACCESS           = 0x97,
+       SCORPION_BANK_CD_ISIDE_HIT              = 0x98,
+       SCORPION_BANK_CD_ISIDE_ACCESS           = 0x99,
+       SCORPION_ISIDE_RD_WAIT                  = 0x9a,
+       SCORPION_DSIDE_RD_WAIT                  = 0x9b,
+       SCORPION_BANK_BYPASS_WRITE              = 0x9c,
+       SCORPION_BANK_AB_NON_CASTOUT            = 0x9d,
+       SCORPION_BANK_AB_L2_CASTOUT             = 0x9e,
+       SCORPION_BANK_CD_NON_CASTOUT            = 0x9f,
+       SCORPION_BANK_CD_L2_CASTOUT             = 0xa0,
+#endif
+       MSM_MAX_EVT
+};
+
+struct scorp_evt {
+       u32 evt_type;
+       u32 val;
+       u8 grp;
+       u32 evt_type_act;
+};
+
+static const struct scorp_evt sc_evt[] = {
+       {SCORPION_ICACHE_EXPL_INV, 0x80000500, 0, 0x4d},
+       {SCORPION_ICACHE_MISS, 0x80050000, 0, 0x4e},
+       {SCORPION_ICACHE_ACCESS, 0x85000000, 0, 0x4f},
+       {SCORPION_ICACHE_CACHEREQ_L2, 0x86000000, 0, 0x4f},
+       {SCORPION_ICACHE_NOCACHE_L2, 0x87000000, 0, 0x4f},
+       {SCORPION_HIQUP_NOPED, 0x80080000, 0, 0x4e},
+       {SCORPION_DATA_ABORT, 0x8000000a, 0, 0x4c},
+       {SCORPION_IRQ, 0x80000a00, 0, 0x4d},
+       {SCORPION_FIQ, 0x800a0000, 0, 0x4e},
+       {SCORPION_ALL_EXCPT, 0x8a000000, 0, 0x4f},
+       {SCORPION_UNDEF, 0x8000000b, 0, 0x4c},
+       {SCORPION_SVC, 0x80000b00, 0, 0x4d},
+       {SCORPION_SMC, 0x800b0000, 0, 0x4e},
+       {SCORPION_PREFETCH_ABORT, 0x8b000000, 0, 0x4f},
+       {SCORPION_INDEX_CHECK, 0x8000000c, 0, 0x4c},
+       {SCORPION_NULL_CHECK, 0x80000c00, 0, 0x4d},
+       {SCORPION_EXPL_ICIALLU, 0x8000000d, 0, 0x4c},
+       {SCORPION_IMPL_ICIALLU, 0x80000d00, 0, 0x4d},
+       {SCORPION_NONICIALLU_BTAC_INV, 0x800d0000, 0, 0x4e},
+       {SCORPION_ICIMVAU_IMPL_ICIALLU, 0x8d000000, 0, 0x4f},
+
+       {SCORPION_SPIPE_ONLY_CYCLES, 0x80000600, 1, 0x51},
+       {SCORPION_XPIPE_ONLY_CYCLES, 0x80060000, 1, 0x52},
+       {SCORPION_DUAL_CYCLES, 0x86000000, 1, 0x53},
+       {SCORPION_DISPATCH_ANY_CYCLES, 0x89000000, 1, 0x53},
+       {SCORPION_FIFO_FULLBLK_CMT, 0x8000000d, 1, 0x50},
+       {SCORPION_FAIL_COND_INST, 0x800d0000, 1, 0x52},
+       {SCORPION_PASS_COND_INST, 0x8d000000, 1, 0x53},
+       {SCORPION_ALLOW_VU_CLK, 0x8000000e, 1, 0x50},
+       {SCORPION_VU_IDLE, 0x80000e00, 1, 0x51},
+       {SCORPION_ALLOW_L2_CLK, 0x800e0000, 1, 0x52},
+       {SCORPION_L2_IDLE, 0x8e000000, 1, 0x53},
+
+       {SCORPION_DTLB_IMPL_INV_SCTLR_DACR, 0x80000001, 2, 0x54},
+       {SCORPION_DTLB_EXPL_INV, 0x80000100, 2, 0x55},
+       {SCORPION_DTLB_MISS, 0x80010000, 2, 0x56},
+       {SCORPION_DTLB_ACCESS, 0x81000000, 2, 0x57},
+       {SCORPION_ITLB_MISS, 0x80000200, 2, 0x55},
+       {SCORPION_ITLB_IMPL_INV, 0x80020000, 2, 0x56},
+       {SCORPION_ITLB_EXPL_INV, 0x82000000, 2, 0x57},
+       {SCORPION_UTLB_D_MISS, 0x80000003, 2, 0x54},
+       {SCORPION_UTLB_D_ACCESS, 0x80000300, 2, 0x55},
+       {SCORPION_UTLB_I_MISS, 0x80030000, 2, 0x56},
+       {SCORPION_UTLB_I_ACCESS, 0x83000000, 2, 0x57},
+       {SCORPION_UTLB_INV_ASID, 0x80000400, 2, 0x55},
+       {SCORPION_UTLB_INV_MVA, 0x80040000, 2, 0x56},
+       {SCORPION_UTLB_INV_ALL, 0x84000000, 2, 0x57},
+       {SCORPION_S2_HOLD_RDQ_UNAVAIL, 0x80000800, 2, 0x55},
+       {SCORPION_S2_HOLD, 0x88000000, 2, 0x57},
+       {SCORPION_S2_HOLD_DEV_OP, 0x80000900, 2, 0x55},
+       {SCORPION_S2_HOLD_ORDER, 0x80090000, 2, 0x56},
+       {SCORPION_S2_HOLD_BARRIER, 0x89000000, 2, 0x57},
+
+       {SCORPION_VIU_DUAL_CYCLE, 0x80000001, 4, 0x5c},
+       {SCORPION_VIU_SINGLE_CYCLE, 0x80000100, 4, 0x5d},
+       {SCORPION_VX_PIPE_WAR_STALL_CYCLES, 0x80000005, 4, 0x5c},
+       {SCORPION_VX_PIPE_WAW_STALL_CYCLES, 0x80000500, 4, 0x5d},
+       {SCORPION_VX_PIPE_RAW_STALL_CYCLES, 0x80050000, 4, 0x5e},
+       {SCORPION_VX_PIPE_LOAD_USE_STALL, 0x80000007, 4, 0x5c},
+       {SCORPION_VS_PIPE_WAR_STALL_CYCLES, 0x80000008, 4, 0x5c},
+       {SCORPION_VS_PIPE_WAW_STALL_CYCLES, 0x80000800, 4, 0x5d},
+       {SCORPION_VS_PIPE_RAW_STALL_CYCLES, 0x80080000, 4, 0x5e},
+       {SCORPION_EXCEPTIONS_INV_OPERATION, 0x8000000b, 4, 0x5c},
+       {SCORPION_EXCEPTIONS_DIV_BY_ZERO, 0x80000b00, 4, 0x5d},
+       {SCORPION_COND_INST_FAIL_VX_PIPE, 0x800b0000, 4, 0x5e},
+       {SCORPION_COND_INST_FAIL_VS_PIPE, 0x8b000000, 4, 0x5f},
+       {SCORPION_EXCEPTIONS_OVERFLOW, 0x8000000c, 4, 0x5c},
+       {SCORPION_EXCEPTIONS_UNDERFLOW, 0x80000c00, 4, 0x5d},
+       {SCORPION_EXCEPTIONS_DENORM, 0x8c000000, 4, 0x5f},
+
+       {SCORPION_BANK_AB_HIT, 0x80000001, 3, 0x58},
+       {SCORPION_BANK_AB_ACCESS, 0x80000100, 3, 0x59},
+       {SCORPION_BANK_CD_HIT, 0x80010000, 3, 0x5a},
+       {SCORPION_BANK_CD_ACCESS, 0x81000000, 3, 0x5b},
+       {SCORPION_BANK_AB_DSIDE_HIT, 0x80000002, 3, 0x58},
+       {SCORPION_BANK_AB_DSIDE_ACCESS, 0x80000200, 3, 0x59},
+       {SCORPION_BANK_CD_DSIDE_HIT, 0x80020000, 3, 0x5a},
+       {SCORPION_BANK_CD_DSIDE_ACCESS, 0x82000000, 3, 0x5b},
+       {SCORPION_BANK_AB_ISIDE_HIT, 0x80000003, 3, 0x58},
+       {SCORPION_BANK_AB_ISIDE_ACCESS, 0x80000300, 3, 0x59},
+       {SCORPION_BANK_CD_ISIDE_HIT, 0x80030000, 3, 0x5a},
+       {SCORPION_BANK_CD_ISIDE_ACCESS, 0x83000000, 3, 0x5b},
+       {SCORPION_ISIDE_RD_WAIT, 0x80000009, 3, 0x58},
+       {SCORPION_DSIDE_RD_WAIT, 0x80090000, 3, 0x5a},
+       {SCORPION_BANK_BYPASS_WRITE, 0x8000000a, 3, 0x58},
+       {SCORPION_BANK_AB_NON_CASTOUT, 0x8000000c, 3, 0x58},
+       {SCORPION_BANK_AB_L2_CASTOUT, 0x80000c00, 3, 0x59},
+       {SCORPION_BANK_CD_NON_CASTOUT, 0x800c0000, 3, 0x5a},
+       {SCORPION_BANK_CD_L2_CASTOUT, 0x8c000000, 3, 0x5b},
+};
+
+static inline void scorpion_pmnc_write(u32 val)
+{
+       val &= PMNC_MASK;
+       asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val));
+}
+
+static inline u32 scorpion_pmnc_read(void)
+{
+       u32 val;
+       asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
+       return val;
+}
+
+static inline u32 scorpion_ccnt_read(void)
+{
+       u32 val;
+       asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));
+       return val;
+}
+
+static inline u32 scorpion_cntn_read(void)
+{
+       u32 val;
+       asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val));
+       return val;
+}
+
+static inline u32 scorpion_pmnc_enable_counter(unsigned int cnt)
+{
+       u32 val;
+
+       if (cnt >= CNTMAX) {
+               pr_err("gator: CPU%u enabling wrong PMNC counter %d\n", smp_processor_id(), cnt);
+               return -1;
+       }
+
+       if (cnt == CCNT)
+               val = CCNT_REG;
+       else
+               val = (1 << (cnt - CNT0));
+
+       asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
+
+       return cnt;
+}
+
+static inline u32 scorpion_pmnc_disable_counter(unsigned int cnt)
+{
+       u32 val;
+
+       if (cnt >= CNTMAX) {
+               pr_err("gator: CPU%u disabling wrong PMNC counter %d\n", smp_processor_id(), cnt);
+               return -1;
+       }
+
+       if (cnt == CCNT)
+               val = CCNT_REG;
+       else
+               val = (1 << (cnt - CNT0));
+
+       asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
+
+       return cnt;
+}
+
+static inline int scorpion_pmnc_select_counter(unsigned int cnt)
+{
+       u32 val;
+
+       if ((cnt == CCNT) || (cnt >= CNTMAX)) {
+               pr_err("gator: CPU%u selecting wrong PMNC counter %d\n", smp_processor_id(), cnt);
+               return -1;
+       }
+
+       val = (cnt - CNT0);
+       asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
+
+       return cnt;
+}
+
+static u32 scorpion_read_lpm0(void)
+{
+       u32 val;
+       asm volatile("mrc p15, 0, %0, c15, c0, 0" : "=r" (val));
+       return val;
+}
+
+static void scorpion_write_lpm0(u32 val)
+{
+       asm volatile("mcr p15, 0, %0, c15, c0, 0" : : "r" (val));
+}
+
+static u32 scorpion_read_lpm1(void)
+{
+       u32 val;
+       asm volatile("mrc p15, 1, %0, c15, c0, 0" : "=r" (val));
+       return val;
+}
+
+static void scorpion_write_lpm1(u32 val)
+{
+       asm volatile("mcr p15, 1, %0, c15, c0, 0" : : "r" (val));
+}
+
+static u32 scorpion_read_lpm2(void)
+{
+       u32 val;
+       asm volatile("mrc p15, 2, %0, c15, c0, 0" : "=r" (val));
+       return val;
+}
+
+static void scorpion_write_lpm2(u32 val)
+{
+       asm volatile("mcr p15, 2, %0, c15, c0, 0" : : "r" (val));
+}
+
+static u32 scorpion_read_l2lpm(void)
+{
+       u32 val;
+       asm volatile("mrc p15, 3, %0, c15, c2, 0" : "=r" (val));
+       return val;
+}
+
+static void scorpion_write_l2lpm(u32 val)
+{
+       asm volatile("mcr p15, 3, %0, c15, c2, 0" : : "r" (val));
+}
+
+static u32 scorpion_read_vlpm(void)
+{
+       u32 val;
+       asm volatile("mrc p10, 7, %0, c11, c0, 0" : "=r" (val));
+       return val;
+}
+
+static void scorpion_write_vlpm(u32 val)
+{
+       asm volatile("mcr p10, 7, %0, c11, c0, 0" : : "r" (val));
+}
+
+struct scorpion_access_funcs {
+       u32 (*read) (void);
+       void (*write) (u32);
+};
+
+struct scorpion_access_funcs scor_func[] = {
+       {scorpion_read_lpm0, scorpion_write_lpm0},
+       {scorpion_read_lpm1, scorpion_write_lpm1},
+       {scorpion_read_lpm2, scorpion_write_lpm2},
+       {scorpion_read_l2lpm, scorpion_write_l2lpm},
+       {scorpion_read_vlpm, scorpion_write_vlpm},
+};
+
+u32 venum_orig_val;
+u32 fp_orig_val;
+
+static void scorpion_pre_vlpm(void)
+{
+       u32 venum_new_val;
+       u32 fp_new_val;
+
+       /* CPACR Enable CP10 access*/
+       asm volatile("mrc p15, 0, %0, c1, c0, 2" : "=r" (venum_orig_val));
+       venum_new_val = venum_orig_val | 0x00300000;
+       asm volatile("mcr p15, 0, %0, c1, c0, 2" : : "r" (venum_new_val));
+       /* Enable FPEXC */
+       asm volatile("mrc p10, 7, %0, c8, c0, 0" : "=r" (fp_orig_val));
+       fp_new_val = fp_orig_val | 0x40000000;
+       asm volatile("mcr p10, 7, %0, c8, c0, 0" : : "r" (fp_new_val));
+}
+
+static void scorpion_post_vlpm(void)
+{
+       /* Restore FPEXC*/
+       asm volatile("mcr p10, 7, %0, c8, c0, 0" : : "r" (fp_orig_val));
+       /* Restore CPACR*/
+       asm volatile("mcr p15, 0, %0, c1, c0, 2" : : "r" (venum_orig_val));
+}
+
+#define COLMN0MASK 0x000000ff
+#define COLMN1MASK 0x0000ff00
+#define COLMN2MASK 0x00ff0000
+static u32 scorpion_get_columnmask(u32 setval)
+{
+       if (setval & COLMN0MASK)
+               return 0xffffff00;
+       else if (setval & COLMN1MASK)
+               return 0xffff00ff;
+       else if (setval & COLMN2MASK)
+               return 0xff00ffff;
+       else
+               return 0x80ffffff;
+}
+
+static void scorpion_evt_setup(u32 gr, u32 setval)
+{
+       u32 val;
+       if (gr == 4)
+               scorpion_pre_vlpm();
+       val = scorpion_get_columnmask(setval) & scor_func[gr].read();
+       val = val | setval;
+       scor_func[gr].write(val);
+       if (gr == 4)
+               scorpion_post_vlpm();
+}
+
+static int get_scorpion_evtinfo(unsigned int evt_type, struct scorp_evt *evtinfo)
+{
+       u32 idx;
+       if ((evt_type < 0x4c) || (evt_type >= MSM_MAX_EVT))
+               return 0;
+       idx = evt_type - 0x4c;
+       if (sc_evt[idx].evt_type == evt_type) {
+               evtinfo->val = sc_evt[idx].val;
+               evtinfo->grp = sc_evt[idx].grp;
+               evtinfo->evt_type_act = sc_evt[idx].evt_type_act;
+               return 1;
+       }
+       return 0;
+}
+
+static inline void scorpion_pmnc_write_evtsel(unsigned int cnt, u32 val)
+{
+       if (scorpion_pmnc_select_counter(cnt) == cnt) {
+               if (val < 0x40) {
+                       asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
+               } else {
+                       u32 zero = 0;
+                       struct scorp_evt evtinfo;
+                       // extract evtinfo.grp and evtinfo.tevt_type_act from val
+                       if (get_scorpion_evtinfo(val, &evtinfo) == 0) return;
+                       asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (evtinfo.evt_type_act));
+                       asm volatile("mcr p15, 0, %0, c9, c15, 0" : : "r" (zero));
+                       scorpion_evt_setup(evtinfo.grp, val);
+               }
+       }
+}
+
+static void scorpion_pmnc_reset_counter(unsigned int cnt)
+{
+       u32 val = 0;
+
+       if (cnt == CCNT) {
+               scorpion_pmnc_disable_counter(cnt);
+
+               asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (val));
+
+               if (pmnc_enabled[cnt] != 0)
+                   scorpion_pmnc_enable_counter(cnt);
+
+       } else if (cnt >= CNTMAX) {
+               pr_err("gator: CPU%u resetting wrong PMNC counter %d\n", smp_processor_id(), cnt);
+       } else {
+               scorpion_pmnc_disable_counter(cnt);
+
+               if (scorpion_pmnc_select_counter(cnt) == cnt)
+                   asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (val));
+
+               if (pmnc_enabled[cnt] != 0)
+                   scorpion_pmnc_enable_counter(cnt);
+       }
+}
+
+static int gator_events_scorpion_create_files(struct super_block *sb, struct dentry *root)
+{
+       struct dentry *dir;
+       int i;
+
+       for (i = 0; i < pmnc_count; i++) {
+               char buf[40];
+               if (i == 0) {
+                       snprintf(buf, sizeof buf, "%s_ccnt", pmnc_name);
+               } else {
+                       snprintf(buf, sizeof buf, "%s_cnt%d", pmnc_name, i-1);
+               }
+               dir = gatorfs_mkdir(sb, root, buf);
+               if (!dir) {
+                       return -1;
+               }
+               gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
+               if (i > 0) {
+                       gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
+               }
+               gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
+       }
+
+       return 0;
+}
+
+static void gator_events_scorpion_online(void)
+{
+       unsigned int cnt;
+
+       if (scorpion_pmnc_read() & PMNC_E) {
+               scorpion_pmnc_write(scorpion_pmnc_read() & ~PMNC_E);
+       }
+
+       /* Initialize & Reset PMNC: C bit and P bit */
+       scorpion_pmnc_write(PMNC_P | PMNC_C);
+
+       for (cnt = CCNT; cnt < CNTMAX; cnt++) {
+               unsigned long event;
+
+               per_cpu(perfPrev, smp_processor_id())[cnt] = 0;
+
+               if (!pmnc_enabled[cnt])
+                       continue;
+
+               // disable counter
+               scorpion_pmnc_disable_counter(cnt);
+
+               event = pmnc_event[cnt] & 255;
+
+               // Set event (if destined for PMNx counters), We don't need to set the event if it's a cycle count
+               if (cnt != CCNT)
+                       scorpion_pmnc_write_evtsel(cnt, event);
+
+               // reset counter
+               scorpion_pmnc_reset_counter(cnt);
+
+               // Enable counter, do not enable interrupt for this counter
+               scorpion_pmnc_enable_counter(cnt);
+       }
+
+       // enable
+       scorpion_pmnc_write(scorpion_pmnc_read() | PMNC_E);
+}
+
+static void gator_events_scorpion_offline(void)
+{
+       scorpion_pmnc_write(scorpion_pmnc_read() & ~PMNC_E);
+
+       // investigate: need to do the clearpmu() here on each counter?
+}
+
+static void gator_events_scorpion_stop(void)
+{
+       unsigned int cnt;
+
+       for (cnt = CCNT; cnt < CNTMAX; cnt++) {
+               pmnc_enabled[cnt] = 0;
+               pmnc_event[cnt] = 0;
+       }
+}
+
+static int gator_events_scorpion_read(int **buffer)
+{
+       int cnt, len = 0;
+       int cpu = smp_processor_id();
+
+       if (!pmnc_count)
+               return 0;
+
+       for (cnt = 0; cnt < pmnc_count; cnt++) {
+               if (pmnc_enabled[cnt]) {
+                       int value;
+                       if (cnt == CCNT) {
+                               value = scorpion_ccnt_read();
+                       } else if (scorpion_pmnc_select_counter(cnt) == cnt) {
+                               value = scorpion_cntn_read();
+                       } else {
+                               value = 0;
+                       }
+                       scorpion_pmnc_reset_counter(cnt);
+                       if (value != per_cpu(perfPrev, cpu)[cnt]) {
+                               per_cpu(perfPrev, cpu)[cnt] = value;
+                               per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
+                               per_cpu(perfCnt, cpu)[len++] = value;
+                       }
+               }
+       }
+
+       // update or discard
+       if (buffer)
+               *buffer = per_cpu(perfCnt, cpu);
+
+       return len;
+}
+
+static struct gator_interface gator_events_scorpion_interface = {
+       .create_files = gator_events_scorpion_create_files,
+       .stop = gator_events_scorpion_stop,
+       .online = gator_events_scorpion_online,
+       .offline = gator_events_scorpion_offline,
+       .read = gator_events_scorpion_read,
+};
+
+
+static void scorpion_clear_pmuregs(void)
+{
+       scorpion_write_lpm0(0);
+       scorpion_write_lpm1(0);
+       scorpion_write_lpm2(0);
+       scorpion_write_l2lpm(0);
+       scorpion_pre_vlpm();
+       scorpion_write_vlpm(0);
+       scorpion_post_vlpm();
+}
+
+int gator_events_scorpion_init(void)
+{
+       unsigned int cnt;
+
+       switch (gator_cpuid()) {
+       case SCORPION:
+               pmnc_name = "Scorpion";
+               pmnc_count = 4;
+               break;
+       case SCORPIONMP:
+               pmnc_name = "ScorpionMP";
+               pmnc_count = 4;
+               break;
+       default:
+               return -1;
+       }
+
+       pmnc_count++; // CNT[n] + CCNT
+
+       for (cnt = CCNT; cnt < CNTMAX; cnt++) {
+               pmnc_enabled[cnt] = 0;
+               pmnc_event[cnt] = 0;
+               pmnc_key[cnt] = gator_events_get_key();
+       }
+
+       scorpion_clear_pmuregs();
+
+       return gator_events_install(&gator_events_scorpion_interface);
+}
+gator_events_init(gator_events_scorpion_init);
index f7cbff2e3d596f85644b695460f7111313e6c32a..8277c3aac3eb3fadc58209406d0d19c29f954d47 100644 (file)
@@ -20,8 +20,6 @@
 #define TMPBUFSIZE 50
 DEFINE_SPINLOCK(gatorfs_lock);
 
-void gator_op_create_files(struct super_block *sb, struct dentry *root);
-
 static struct inode *gatorfs_get_inode(struct super_block *sb, int mode)
 {
        struct inode *inode = new_inode(sb);
index a1ab776d991d85f8ca7d49e57fc5aeeac95f8bda..340756e6f5249c556004f7d8aa43d42e92b71db0 100644 (file)
@@ -7,9 +7,8 @@
  *
  */
 
-static unsigned long gator_protocol_version = 4;
+static unsigned long gator_protocol_version = 5;
 
-#include "gator.h"
 #include <linux/slab.h>
 #include <linux/cpu.h>
 #include <linux/sched.h>
@@ -20,23 +19,26 @@ static unsigned long gator_protocol_version = 4;
 #include <linux/pagemap.h>
 #include <asm/uaccess.h>
 
+#include "gator.h"
+#include "gator_events.h"
+
 #ifndef CONFIG_GENERIC_TRACER
 #ifndef CONFIG_TRACING
-#warning gator requires the kernel to have CONFIG_GENERIC_TRACER or CONFIG_TRACING defined
+#error gator requires the kernel to have CONFIG_GENERIC_TRACER or CONFIG_TRACING defined
 #endif
 #endif
 
 #ifndef CONFIG_PROFILING
-#warning gator requires the kernel to have CONFIG_PROFILING defined
+#error gator requires the kernel to have CONFIG_PROFILING defined
 #endif
 
 #ifndef CONFIG_HIGH_RES_TIMERS
-#warning gator requires the kernel to have CONFIG_HIGH_RES_TIMERS defined
+#error gator requires the kernel to have CONFIG_HIGH_RES_TIMERS defined
 #endif
 
 #ifdef CONFIG_SMP
 #ifndef CONFIG_LOCAL_TIMERS
-#warning gator requires the kernel to have CONFIG_LOCAL_TIMERS defined on SMP systems
+#error gator requires the kernel to have CONFIG_LOCAL_TIMERS defined on SMP systems
 #endif
 #endif
 
@@ -80,7 +82,7 @@ static unsigned long gator_backtrace_depth;
 static unsigned long gator_started;
 static unsigned long gator_buffer_opened;
 static unsigned long gator_timer_count;
-static unsigned long gator_sync_freq;
+static unsigned long gator_streaming;
 static int gator_master_tick;
 static DEFINE_MUTEX(start_mutex);
 static DEFINE_MUTEX(gator_buffer_mutex);
@@ -104,6 +106,7 @@ static DEFINE_PER_CPU(int, gator_first_time);
  ******************************************************************************/
 static void gator_buffer_write_packed_int(int cpu, unsigned int x);
 static void gator_buffer_write_string(int cpu, char *x);
+static int  gator_write_packed_int(char *buffer, unsigned int x);
 static void gator_add_trace(int cpu, unsigned int address);
 static uint64_t gator_get_time(void);
 
@@ -114,7 +117,6 @@ static uint64_t gator_get_time(void);
 #include "gator_trace_sched.c"
 #include "gator_backtrace.c"
 #include "gator_annotate.c"
-#include "gator_events.c"
 #include "gator_fs.c"
 
 /******************************************************************************
@@ -204,6 +206,36 @@ static void gator_buffer_write_packed_int(int cpu, unsigned int x)
        }
 }
 
+static int gator_write_packed_int(char *buffer, unsigned int x)
+{
+       if ((x & 0xffffff80) == 0) {
+               buffer[0] = x & 0x7f;
+               return 1;
+       } else if ((x & 0xffffc000) == 0) {
+               buffer[0] = x | 0x80;
+               buffer[1] = (x>>7) & 0x7f;
+               return 2;
+       } else if ((x & 0xffe00000) == 0) {
+               buffer[0] = x | 0x80;
+               buffer[1] = (x>>7) | 0x80;
+               buffer[2] = (x>>14) & 0x7f;
+               return 3;
+       } else if ((x & 0xf0000000) == 0) {
+               buffer[0] = x | 0x80;
+               buffer[1] = (x>>7) | 0x80;
+               buffer[2] = (x>>14) | 0x80;
+               buffer[3] = (x>>21) & 0x7f;
+               return 4;
+       } else {
+               buffer[0] = x | 0x80;
+               buffer[1] = (x>>7) | 0x80;
+               buffer[2] = (x>>14) | 0x80;
+               buffer[3] = (x>>21) | 0x80;
+               buffer[4] = (x>>28) & 0x0f;
+               return 5;
+       }
+}
+
 static void gator_buffer_write_bytes(int cpu, char *x, int len)
 {
        uint32_t write = per_cpu(use_buffer_write, cpu);
@@ -244,7 +276,7 @@ static void gator_buffer_commit(int cpu)
 
 static void gator_buffer_check(int cpu, int tick)
 {
-       if (gator_sync_freq && !(tick % gator_sync_freq)) {
+       if (!(tick % gator_timer_count)) {
                int c, sync;
                spin_lock(&gator_commit_lock);
                // synchronize, if all online cpus have the same tick waypoint
@@ -258,7 +290,6 @@ static void gator_buffer_check(int cpu, int tick)
                if (sync) {
                        gator_buffer_write_packed_int(cpu, PROTOCOL_CPU_SYNC);
                }
-               // commit the buffer
                gator_buffer_commit(cpu);
                spin_unlock(&gator_commit_lock);
        } else {
@@ -336,46 +367,27 @@ static void gator_write_packet(int cpu, int type, int len, int *buffer)
        }
 }
 
-static void gator_write_annotate(int cpu, int len, int *buffer)
-{
-       int pos = 0;
-
-       while (pos < len) {
-               unsigned int tid = buffer[pos++];
-               unsigned int bytes = buffer[pos++];
-               unsigned int words = (bytes + 3) / 4;
-               char *ptr = (char *)&buffer[pos];
-               pos += words;
-
-               gator_buffer_write_packed_int(cpu, PROTOCOL_ANNOTATE);
-               gator_buffer_write_packed_int(cpu, tid);
-               gator_buffer_write_packed_int(cpu, bytes);
-               gator_buffer_write_bytes(cpu, ptr, bytes);
-       }
-}
-
 /******************************************************************************
  * Interrupt Processing
  ******************************************************************************/
-static gator_interface *gi = NULL;
+static LIST_HEAD(gator_events);
 
 static void gator_timer_interrupt(void)
 {
        struct pt_regs * const regs = get_irq_regs();
-       int cpu = raw_smp_processor_id();
+       int cpu = smp_processor_id();
        int *buffer, len, tick;
-       gator_interface *i;
+       struct gator_interface *gi;
 
        // check full backtrace has enough space, otherwise may
        // have breaks between samples in the same callstack
        if (per_cpu(gator_first_time, cpu)) {
                per_cpu(gator_first_time, cpu) = 0;
 
-               for (i = gi; i != NULL; i = i->next) {
-                       if (i->read) {
-                               i->read(NULL);
-                       }
-               }
+               list_for_each_entry(gi, &gator_events, list)
+                       if (gi->read)
+                               gi->read(NULL);
+
                return;
        }
 
@@ -388,18 +400,12 @@ static void gator_timer_interrupt(void)
                gator_write_packet(cpu, PROTOCOL_SCHEDULER_TRACE, len, buffer);
        }
 
-       // Output annotate
-       len = gator_annotate_read(&buffer);
-       if (len > 0)
-               gator_write_annotate(cpu, len, buffer);
-
        // Output counters
-       for (i = gi; i != NULL; i = i->next) {
-               if (i->read) {
-                       len = i->read(&buffer);
-                       if (len > 0) {
+       list_for_each_entry(gi, &gator_events, list) {
+               if (gi->read) {
+                       len = gi->read(&buffer);
+                       if (len > 0)
                                gator_write_packet(cpu, PROTOCOL_COUNTERS, len, buffer);
-                       }
                }
        }
 
@@ -444,18 +450,16 @@ static void __gator_timer_offline(void *unused)
 {
        int cpu = smp_processor_id();
        if (per_cpu(hrtimer_is_active, cpu)) {
-               gator_interface *i;
+               struct gator_interface *gi;
                struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu);
                hrtimer_cancel(hrtimer);
                per_cpu(hrtimer_is_active, cpu) = 0;
                gator_buffer_commit(cpu);
 
                // offline any events
-               for (i = gi; i != NULL; i = i->next) {
-                       if (i->offline) {
-                               i->offline();
-                       }
-               }
+               list_for_each_entry(gi, &gator_events, list)
+                       if (gi->offline)
+                               gi->offline();
        }
 }
 
@@ -476,7 +480,7 @@ static void __gator_timer_online(void *unused)
 {
        int cpu = smp_processor_id();
        if (!per_cpu(hrtimer_is_active, cpu)) {
-               gator_interface *i;
+               struct gator_interface *gi;
                struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu);
                hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
                hrtimer->function = gator_hrtimer_notify;
@@ -486,11 +490,9 @@ static void __gator_timer_online(void *unused)
                per_cpu(hrtimer_is_active, cpu) = 1;
 
                // online any events
-               for (i = gi; i != NULL; i = i->next) {
-                       if (i->online) {
-                               i->online();
-                       }
-               }
+               list_for_each_entry(gi, &gator_events, list)
+                       if (gi->online)
+                               gi->online();
        }
 }
 
@@ -566,46 +568,23 @@ static void gator_notifier_stop(void)
 /******************************************************************************
  * Main
  ******************************************************************************/
-int gator_event_install(int (*event_install)(gator_interface *))
+int gator_events_install(struct gator_interface *interface)
 {
-       gator_interface *ni = (gator_interface*)kmalloc(sizeof(gator_interface), GFP_KERNEL);
-       if (ni == NULL) {
-               return -1;
-       }
-
-       ni->create_files = NULL;
-       ni->init = NULL;
-       ni->start = NULL;
-       ni->stop = NULL;
-       ni->online = NULL;
-       ni->offline = NULL;
-       ni->read = NULL;
-       ni->next = NULL;
-
-       // Initialize ni gator interface
-       if (!event_install(ni)) {
-               if (gi == NULL) {
-                       // Set gi to point to the first gator interface
-                       gi = ni;
-               } else {
-                       // Link the gator interfaces
-                       gator_interface *i = gi;
-                       while (i->next) {
-                               i = i->next;
-                       }
-                       i->next = ni;
-               }
-       } else {
-               kfree(ni);
-       }
+       list_add_tail(&interface->list, &gator_events);
 
        return 0;
 }
 
+int gator_events_get_key(void)
+{
+       static int key;
+
+       return key++;
+}
+
 static int gator_init(void)
 {
-       gator_interface *i;
-       int key = 0;
+       int i;
 
        if (gator_timer_init())
                return -1;
@@ -614,32 +593,33 @@ static int gator_init(void)
        if (gator_annotate_init())
                return -1;
 
-       // set up gator interface linked list structure
-       if (gator_events_install())
-               return -1;
-
-       // initialize all events
-       for (i = gi; i != NULL; i = i->next) {
-               if (i->init) {
-                       if (i->init(&key)) {
-                               return -1;
-                       }
-               }
-       }
+       // events sources (gator_events.h, generated by gator_events.sh)
+       for (i = 0; i < ARRAY_SIZE(gator_events_list); i++)
+               if (gator_events_list[i])
+                       gator_events_list[i]();
 
        return 0;
 }
 
 static int gator_start(void)
 {
-       gator_interface *i, *f;
+       struct gator_interface *gi;
 
        // start all events
-       for (i = gi; i != NULL; i = i->next) {
-               if (i->start) {
-                       if (i->start()) {
-                               goto events_failure;
+       list_for_each_entry(gi, &gator_events, list) {
+               if (gi->start && gi->start() != 0) {
+                       struct list_head *ptr = gi->list.prev;
+
+                       while (ptr != &gator_events) {
+                               gi = list_entry(ptr, struct gator_interface,
+                                               list);
+
+                               if (gi->stop)
+                                       gi->stop();
+
+                               ptr = ptr->prev;
                        }
+                       goto events_failure;
                }
        }
 
@@ -662,23 +642,18 @@ sched_failure:
        gator_annotate_stop();
 annotate_failure:
 events_failure:
-       for (f = gi; f != i; f = f->next) {
-               f->stop();
-       }
 
        return -1;
 }
 
 static void gator_stop(void)
 {
-       gator_interface *i;
+       struct gator_interface *gi;
 
        // stop all events
-       for (i = gi; i != NULL; i = i->next) {
-               if (i->stop) {
-                       i->stop();
-               }
-       }
+       list_for_each_entry(gi, &gator_events, list)
+               if (gi->stop)
+                       gi->stop();
 
        gator_annotate_stop();
        gator_trace_sched_stop();
@@ -690,13 +665,7 @@ static void gator_stop(void)
 
 static void gator_exit(void)
 {
-       gator_interface *i = gi;
-
-       while (i) {
-               gator_interface *p = i;
-               i = i->next;
-               kfree(p);
-       }
+       gator_annotate_exit();
 }
 
 /******************************************************************************
@@ -894,6 +863,7 @@ static ssize_t event_buffer_read(struct file *file, char __user *buf,
        int retval = -EINVAL;
        int commit, length1, length2, read;
        char *buffer1, *buffer2;
+       char annotate_header[6];
        int cpu;
 
        /* do not handle partial reads */
@@ -902,34 +872,43 @@ static ssize_t event_buffer_read(struct file *file, char __user *buf,
 
        // sleep until the condition is true or a signal is received
        // the condition is checked each time gator_buffer_wait is woken up
-       wait_event_interruptible(gator_buffer_wait, buffer_commit_ready() || !gator_started);
+       wait_event_interruptible(gator_buffer_wait, buffer_commit_ready() || gator_annotate_ready() || !gator_started);
 
        if (signal_pending(current))
                return -EINTR;
 
-       if (!buffer_commit_ready())
-               return 0;
-
-       buffer_commit_read(&cpu, &read, &commit);
+       retval = -EFAULT;
 
        mutex_lock(&gator_buffer_mutex);
 
-       retval = -EFAULT;
+       if (buffer_commit_ready()) {
+               buffer_commit_read(&cpu, &read, &commit);
 
-       /* May happen if the buffer is freed during pending reads. */
-       if (!per_cpu(use_buffer, cpu)) {
-               retval = -EFAULT;
-               goto out;
-       }
+               /* May happen if the buffer is freed during pending reads. */
+               if (!per_cpu(use_buffer, cpu)) {
+                       retval = -EFAULT;
+                       goto out;
+               }
 
-       /* determine the size of two halves */
-       length1 = commit - read;
-       length2 = 0;
-       buffer1 = &(per_cpu(use_buffer, cpu)[read]);
-       buffer2 = &(per_cpu(use_buffer, cpu)[0]);
-       if (length1 < 0) {
-               length1 = use_buffer_size - read;
-               length2 = commit;
+               /* determine the size of two halves */
+               length1 = commit - read;
+               length2 = 0;
+               buffer1 = &(per_cpu(use_buffer, cpu)[read]);
+               buffer2 = &(per_cpu(use_buffer, cpu)[0]);
+               if (length1 < 0) {
+                       length1 = use_buffer_size - read;
+                       length2 = commit;
+               }
+       } else if (gator_annotate_ready()) {
+               length2 = gator_annotate_read(&buffer2);
+               if (!length2)
+                       goto out;
+               annotate_header[0] = PROTOCOL_ANNOTATE;
+               length1 = gator_write_packed_int(&annotate_header[1], length2) + 1;
+               buffer1 = annotate_header;
+       } else {
+               retval = 0;
+               goto out;
        }
 
        /* start, middle or end */
@@ -952,8 +931,8 @@ static ssize_t event_buffer_read(struct file *file, char __user *buf,
        wake_up(&gator_buffer_wait);
 
 out:
-       // do not adjust network stats if in non-streaming buffer mode
-       if (gator_sync_freq)
+       // only adjust network stats if in streaming mode
+       if (gator_streaming)
                gator_net_traffic += retval;
        mutex_unlock(&gator_buffer_mutex);
        return retval;
@@ -1009,7 +988,7 @@ static const struct file_operations cpu_type_fops = {
 void gator_op_create_files(struct super_block *sb, struct dentry *root)
 {
        struct dentry *dir;
-       gator_interface *i;
+       struct gator_interface *gi;
        int cpu;
 
        /* reinitialize default values */
@@ -1018,7 +997,7 @@ void gator_op_create_files(struct super_block *sb, struct dentry *root)
                gator_cpu_cores++;
        }
        gator_buffer_size =     BUFFER_SIZE_DEFAULT;
-       gator_sync_freq = SYNC_FREQ_DEFAULT;
+       gator_streaming = 1;
 
        gatorfs_create_file(sb, root, "enable", &enable_fops);
        gatorfs_create_file(sb, root, "buffer", &gator_event_buffer_fops);
@@ -1027,7 +1006,7 @@ void gator_op_create_files(struct super_block *sb, struct dentry *root)
        gatorfs_create_ulong(sb, root, "cpu_cores", &gator_cpu_cores);
        gatorfs_create_ulong(sb, root, "buffer_size", &gator_buffer_size);
        gatorfs_create_ulong(sb, root, "tick", &gator_timer_count);
-       gatorfs_create_ulong(sb, root, "sync_freq", &gator_sync_freq);
+       gatorfs_create_ulong(sb, root, "streaming", &gator_streaming);
        gatorfs_create_ro_ulong(sb, root, "version", &gator_protocol_version);
 
        // Annotate interface
@@ -1035,18 +1014,14 @@ void gator_op_create_files(struct super_block *sb, struct dentry *root)
 
        // Linux Events
        dir = gatorfs_mkdir(sb, root, "events");
-       for (i = gi; i != NULL; i = i->next) {
-               if (i->create_files) {
-                       i->create_files(sb, dir);
-               }
-       }
+       list_for_each_entry(gi, &gator_events, list)
+               if (gi->create_files)
+                       gi->create_files(sb, dir);
 }
 
 /******************************************************************************
  * Module
  ******************************************************************************/
-static int gator_initialized;
-
 static int __init gator_module_init(void)
 {
        if (gatorfs_register()) {
@@ -1058,7 +1033,6 @@ static int __init gator_module_init(void)
                return -1;
        }
 
-       gator_initialized = 1;
 #ifdef GATOR_DEBUG
        pr_err("gator_module_init");
 #endif
@@ -1072,10 +1046,7 @@ static void __exit gator_module_exit(void)
 #endif
        tracepoint_synchronize_unregister();
        gatorfs_unregister();
-       if (gator_initialized) {
-               gator_initialized = 0;
-               gator_exit();
-       }
+       gator_exit();
 }
 
 module_init(gator_module_init);