diff options
author | Pawel Moll <pawel.moll@arm.com> | 2011-08-03 11:30:26 +0100 |
---|---|---|
committer | Pawel Moll <pawel.moll@arm.com> | 2011-08-03 11:30:26 +0100 |
commit | 7c366b2d106bd14742cc3446f874e520d473703d (patch) | |
tree | 3995b9c4b72d1529dafa810c80d05068e6f85e3b | |
parent | c5e21c20e9c3b00a3057965e7ab0a55a5873594b (diff) |
gator: ARM DS-5.6 Streamline gator driverDS-5.6
Signed-off-by: Pawel Moll <pawel.moll@arm.com>
-rw-r--r-- | Makefile | 25 | ||||
-rw-r--r-- | gator.h | 19 | ||||
-rw-r--r-- | gator_annotate.c | 109 | ||||
-rw-r--r-- | gator_cookies.c | 4 | ||||
-rw-r--r-- | gator_events.sh | 19 | ||||
-rw-r--r-- | gator_events_armv6.c | 53 | ||||
-rw-r--r-- | gator_events_armv7.c | 217 | ||||
-rw-r--r-- | gator_events_block.c | 41 | ||||
-rw-r--r-- | gator_events_irq.c | 43 | ||||
-rw-r--r-- | gator_events_meminfo.c | 40 | ||||
-rw-r--r-- | gator_events_mmaped.c | 196 | ||||
-rw-r--r-- | gator_events_net.c | 45 | ||||
-rw-r--r-- | gator_events_pl310.c | 176 | ||||
-rw-r--r-- | gator_events_sched.c | 36 | ||||
-rw-r--r-- | gator_events_scorpion.c | 661 | ||||
-rw-r--r-- | gator_fs.c | 2 | ||||
-rw-r--r-- | gator_main.c | 291 |
17 files changed, 1476 insertions, 501 deletions
@@ -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: @@ -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_ diff --git a/gator_annotate.c b/gator_annotate.c index f261f73..d8d86af 100644 --- a/gator_annotate.c +++ b/gator_annotate.c @@ -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; } diff --git a/gator_cookies.c b/gator_cookies.c index 70fece0..64be841 100644 --- a/gator_cookies.c +++ b/gator_cookies.c @@ -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 index 0000000..5467dd6 --- /dev/null +++ b/gator_events.sh @@ -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 diff --git a/gator_events_armv6.c b/gator_events_armv6.c index c571e44..7b1d875 100644 --- a/gator_events_armv6.c +++ b/gator_events_armv6.c @@ -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); diff --git a/gator_events_armv7.c b/gator_events_armv7.c index 5a3268f..0b84745 100644 --- a/gator_events_armv7.c +++ b/gator_events_armv7.c @@ -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); diff --git a/gator_events_block.c b/gator_events_block.c index f32d8ef..cbfed86 100644 --- a/gator_events_block.c +++ b/gator_events_block.c @@ -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); diff --git a/gator_events_irq.c b/gator_events_irq.c index 7bbbd4b..36a6589 100644 --- a/gator_events_irq.c +++ b/gator_events_irq.c @@ -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); diff --git a/gator_events_meminfo.c b/gator_events_meminfo.c index 1b576f8..f1595bd 100644 --- a/gator_events_meminfo.c +++ b/gator_events_meminfo.c @@ -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 index 0000000..6884684 --- /dev/null +++ b/gator_events_mmaped.c @@ -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); diff --git a/gator_events_net.c b/gator_events_net.c index 15a395e..a921586 100644 --- a/gator_events_net.c +++ b/gator_events_net.c @@ -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 index 0000000..0ef0cf3 --- /dev/null +++ b/gator_events_pl310.c @@ -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); diff --git a/gator_events_sched.c b/gator_events_sched.c index 138b7e4..7e9db60 100644 --- a/gator_events_sched.c +++ b/gator_events_sched.c @@ -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 index 0000000..d831a50 --- /dev/null +++ b/gator_events_scorpion.c @@ -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); @@ -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); diff --git a/gator_main.c b/gator_main.c index a1ab776..340756e 100644 --- a/gator_main.c +++ b/gator_main.c @@ -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); |