summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPawel Moll2011-08-03 05:30:26 -0500
committerPawel Moll2011-08-03 05:30:26 -0500
commit7c366b2d106bd14742cc3446f874e520d473703d (patch)
tree3995b9c4b72d1529dafa810c80d05068e6f85e3b
parentc5e21c20e9c3b00a3057965e7ab0a55a5873594b (diff)
downloadarm-ds5-gator-7c366b2d106bd14742cc3446f874e520d473703d.tar.gz
arm-ds5-gator-7c366b2d106bd14742cc3446f874e520d473703d.tar.xz
arm-ds5-gator-7c366b2d106bd14742cc3446f874e520d473703d.zip
gator: ARM DS-5.6 Streamline gator driver
Signed-off-by: Pawel Moll <pawel.moll@arm.com>
-rw-r--r--Makefile25
-rw-r--r--gator.h19
-rw-r--r--gator_annotate.c109
-rw-r--r--gator_cookies.c4
-rw-r--r--gator_events.sh19
-rw-r--r--gator_events_armv6.c53
-rw-r--r--gator_events_armv7.c217
-rw-r--r--gator_events_block.c41
-rw-r--r--gator_events_irq.c43
-rw-r--r--gator_events_meminfo.c40
-rw-r--r--gator_events_mmaped.c196
-rw-r--r--gator_events_net.c45
-rw-r--r--gator_events_pl310.c176
-rw-r--r--gator_events_sched.c36
-rw-r--r--gator_events_scorpion.c661
-rw-r--r--gator_fs.c2
-rw-r--r--gator_main.c291
17 files changed, 1476 insertions, 501 deletions
diff --git a/Makefile b/Makefile
index 0583ae3..b3680e1 100644
--- a/Makefile
+++ b/Makefile
@@ -2,15 +2,34 @@ ifneq ($(KERNELRELEASE),)
2 2
3obj-m := gator.o 3obj-m := gator.o
4 4
5gator-objs := gator_main.o \ 5gator-y := gator_main.o \
6 gator_events_armv6.o \
7 gator_events_armv7.o \
8 gator_events_irq.o \ 6 gator_events_irq.o \
9 gator_events_sched.o \ 7 gator_events_sched.o \
10 gator_events_net.o \ 8 gator_events_net.o \
11 gator_events_block.o \ 9 gator_events_block.o \
12 gator_events_meminfo.o 10 gator_events_meminfo.o
13 11
12gator-y += gator_events_mmaped.o
13
14ifneq ($(GATOR_WITH_MALI_SUPPORT),)
15gator-y += gator_events_mali.o
16endif
17
18gator-$(CONFIG_ARM) += gator_events_armv6.o \
19 gator_events_armv7.o \
20 gator_events_pl310.o
21
22$(obj)/gator_main.o: gator_events.h
23
24clean-files := gator_events.h
25
26 chk_events.h = :
27 quiet_chk_events.h = echo ' CHK $@'
28silent_chk_events.h = :
29gator_events.h: FORCE
30 @$($(quiet)chk_events.h)
31 $(Q)cd $(obj) ; $(CONFIG_SHELL) $(obj)/gator_events.sh $@
32
14else 33else
15 34
16all: 35all:
diff --git a/gator.h b/gator.h
index f0c95bf..9d802a3 100644
--- a/gator.h
+++ b/gator.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright 2010 ARM, Ltd. 2 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -12,6 +12,7 @@
12#include <linux/version.h> 12#include <linux/version.h>
13#include <linux/fs.h> 13#include <linux/fs.h>
14#include <linux/mm.h> 14#include <linux/mm.h>
15#include <linux/list.h>
15 16
16/****************************************************************************** 17/******************************************************************************
17 * Filesystem 18 * Filesystem
@@ -28,6 +29,8 @@ int gatorfs_create_ulong(struct super_block *sb, struct dentry *root,
28int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root, 29int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
29 char const *name, unsigned long *val); 30 char const *name, unsigned long *val);
30 31
32void gator_op_create_files(struct super_block *sb, struct dentry *root);
33
31/****************************************************************************** 34/******************************************************************************
32 * Tracepoints 35 * Tracepoints
33 ******************************************************************************/ 36 ******************************************************************************/
@@ -52,21 +55,25 @@ int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
52/****************************************************************************** 55/******************************************************************************
53 * Events 56 * Events
54 ******************************************************************************/ 57 ******************************************************************************/
55struct __gator_interface { 58struct gator_interface {
56 int (*create_files)(struct super_block *sb, struct dentry *root); 59 int (*create_files)(struct super_block *sb, struct dentry *root);
57 int (*init)(int *key);
58 int (*start)(void); 60 int (*start)(void);
59 void (*stop)(void); 61 void (*stop)(void);
60 void (*online)(void); 62 void (*online)(void);
61 void (*offline)(void); 63 void (*offline)(void);
62 int (*read)(int **buffer); 64 int (*read)(int **buffer);
63 struct __gator_interface *next; 65 struct list_head list;
64}; 66};
65 67
66typedef struct __gator_interface gator_interface; 68#define gator_events_init(initfn) \
69 static inline int __gator_events_init_test(void) \
70 { return initfn(); }
67 71
68int gator_event_install(int (*event_install)(gator_interface *)); 72int gator_events_install(struct gator_interface *interface);
73int gator_events_get_key(void);
74extern u32 gator_cpuid(void);
69 75
70extern unsigned long gator_net_traffic; 76extern unsigned long gator_net_traffic;
71 77
78
72#endif // GATOR_H_ 79#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 @@
15#include <asm/current.h> 15#include <asm/current.h>
16#include <linux/spinlock.h> 16#include <linux/spinlock.h>
17 17
18#define INSTSIZE 1024 18#define ANNOTATE_SIZE (16*1024)
19static DEFINE_SPINLOCK(annotate_lock); 19static DEFINE_SPINLOCK(annotate_lock);
20static char *annotateBuf; 20static char *annotateBuf;
21static char *annotateBuf0; 21static char *annotateBuf0;
@@ -25,35 +25,42 @@ static int annotateSel;
25 25
26static ssize_t annotate_write(struct file *file, char const __user *buf, size_t count, loff_t *offset) 26static ssize_t annotate_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
27{ 27{
28 char tempBuffer[32]; 28 char tempBuffer[512];
29 unsigned long flags;
30 int retval, remaining, size; 29 int retval, remaining, size;
31 30
32 if (*offset) 31 if (*offset)
33 return -EINVAL; 32 return -EINVAL;
34 33
35 // determine size to capture 34 // determine size to capture
36 remaining = INSTSIZE - annotatePos - 24; // leave some extra space 35 remaining = ANNOTATE_SIZE - annotatePos - 256; // pad for headers and release
37 size = count < sizeof(tempBuffer) ? count : sizeof(tempBuffer); 36 size = count < sizeof(tempBuffer) ? count : sizeof(tempBuffer);
38 size = size < remaining ? size : remaining; 37 size = size < remaining ? size : remaining;
39 if (size <= 0) 38 if (size <= 0) {
39 wake_up(&gator_buffer_wait);
40 return 0; 40 return 0;
41 }
41 42
42 // copy from user space 43 // copy from user space
43 retval = copy_from_user(tempBuffer, buf, size); 44 retval = copy_from_user(tempBuffer, buf, size);
44 if (retval == 0) { 45 if (retval == 0) {
45 // synchronize shared variables annotateBuf and annotatePos 46 // synchronize shared variables annotateBuf and annotatePos
46 spin_lock_irqsave(&annotate_lock, flags); 47 spin_lock(&annotate_lock);
47 if (!annotateBuf) { 48 if (annotateBuf) {
48 size = -EINVAL; 49 uint32_t tid = current->pid;
49 } else { 50 uint32_t tick = gator_master_tick;
50 *(int*)&annotateBuf[annotatePos + 0] = current->pid; // thread id 51 uint64_t time = gator_get_time();
51 *(int*)&annotateBuf[annotatePos + 4] = size; // length in bytes 52 uint32_t cpuid = smp_processor_id();
52 memcpy(&annotateBuf[annotatePos + 8], tempBuffer, size); // data 53 int pos = annotatePos;
53 annotatePos = annotatePos + 8 + size; // increment position 54 pos += gator_write_packed_int(&annotateBuf[pos], tid);
54 annotatePos = (annotatePos + 3) & ~3; // align to 4-byte boundary 55 pos += gator_write_packed_int(&annotateBuf[pos], tick);
56 pos += gator_write_packed_int(&annotateBuf[pos], time);
57 pos += gator_write_packed_int(&annotateBuf[pos], time >> 32);
58 pos += gator_write_packed_int(&annotateBuf[pos], cpuid);
59 pos += gator_write_packed_int(&annotateBuf[pos], size);
60 memcpy(&annotateBuf[pos], tempBuffer, size);
61 annotatePos = pos + size;
55 } 62 }
56 spin_unlock_irqrestore(&annotate_lock, flags); 63 spin_unlock(&annotate_lock);
57 64
58 // return the number of bytes written 65 // return the number of bytes written
59 retval = size; 66 retval = size;
@@ -64,64 +71,96 @@ static ssize_t annotate_write(struct file *file, char const __user *buf, size_t
64 return retval; 71 return retval;
65} 72}
66 73
74static int annotate_release(struct inode *inode, struct file *file)
75{
76 int remaining = ANNOTATE_SIZE - annotatePos;
77 if (remaining < 16) {
78 return -EFAULT;
79 }
80
81 spin_lock(&annotate_lock);
82 if (annotateBuf) {
83 uint32_t tid = current->pid;
84 uint32_t tick = gator_master_tick;
85 int pos = annotatePos;
86 pos += gator_write_packed_int(&annotateBuf[pos], tid);
87 pos += gator_write_packed_int(&annotateBuf[pos], tick);
88 pos += gator_write_packed_int(&annotateBuf[pos], 0); // time
89 pos += gator_write_packed_int(&annotateBuf[pos], 0); // time
90 pos += gator_write_packed_int(&annotateBuf[pos], 0); // cpuid
91 pos += gator_write_packed_int(&annotateBuf[pos], 0); // size
92 annotatePos = pos;
93 }
94 spin_unlock(&annotate_lock);
95
96 return 0;
97}
98
67static const struct file_operations annotate_fops = { 99static const struct file_operations annotate_fops = {
68 .write = annotate_write 100 .write = annotate_write,
101 .release = annotate_release
69}; 102};
70 103
71int gator_annotate_create_files(struct super_block *sb, struct dentry *root) 104static int gator_annotate_create_files(struct super_block *sb, struct dentry *root)
72{ 105{
73 annotateBuf = annotateBuf0 = annotateBuf1 = NULL; 106 annotateBuf = NULL;
74 return gatorfs_create_file_perm(sb, root, "annotate", &annotate_fops, 0666); 107 return gatorfs_create_file_perm(sb, root, "annotate", &annotate_fops, 0666);
75} 108}
76 109
77int gator_annotate_init(void) 110static int gator_annotate_init(void)
78{ 111{
112 annotateBuf0 = kmalloc(ANNOTATE_SIZE, GFP_KERNEL);
113 annotateBuf1 = kmalloc(ANNOTATE_SIZE, GFP_KERNEL);
114 if (!annotateBuf0 || !annotateBuf1)
115 return -1;
79 return 0; 116 return 0;
80} 117}
81 118
82int gator_annotate_start(void) 119static int gator_annotate_start(void)
83{ 120{
84 annotatePos = annotateSel = 0; 121 annotatePos = annotateSel = 0;
85 annotateBuf0 = kmalloc(INSTSIZE, GFP_KERNEL);
86 annotateBuf1 = kmalloc(INSTSIZE, GFP_KERNEL);
87 annotateBuf = annotateBuf0; 122 annotateBuf = annotateBuf0;
88 if (!annotateBuf0 || !annotateBuf1)
89 return -1;
90 return 0; 123 return 0;
91} 124}
92 125
93void gator_annotate_stop(void) 126static void gator_annotate_stop(void)
94{ 127{
95 unsigned long flags; 128 spin_lock(&annotate_lock);
96 spin_lock_irqsave(&annotate_lock, flags); 129 annotateBuf = NULL;
130 spin_unlock(&annotate_lock);
131}
97 132
133static void gator_annotate_exit(void)
134{
135 spin_lock(&annotate_lock);
98 kfree(annotateBuf0); 136 kfree(annotateBuf0);
99 kfree(annotateBuf1); 137 kfree(annotateBuf1);
100 annotateBuf = annotateBuf0 = annotateBuf1 = NULL; 138 annotateBuf = annotateBuf0 = annotateBuf1 = NULL;
139 spin_unlock(&annotate_lock);
140}
101 141
102 spin_unlock_irqrestore(&annotate_lock, flags); 142static int gator_annotate_ready(void)
143{
144 return annotatePos && annotateBuf;
103} 145}
104 146
105int gator_annotate_read(int **buffer) 147static int gator_annotate_read(char **buffer)
106{ 148{
107 int len; 149 int len;
108 150
109 if (smp_processor_id() || !annotatePos || !annotateBuf) 151 if (!gator_annotate_ready())
110 return 0; 152 return 0;
111 153
112 annotateSel = !annotateSel; 154 annotateSel = !annotateSel;
113 155
114 if (buffer) 156 if (buffer)
115 *buffer = (int *)annotateBuf; 157 *buffer = annotateBuf;
116 158
117 spin_lock(&annotate_lock); 159 spin_lock(&annotate_lock);
118
119 len = annotatePos; 160 len = annotatePos;
120 annotatePos = 0; 161 annotatePos = 0;
121 annotateBuf = annotateSel ? annotateBuf1 : annotateBuf0; 162 annotateBuf = annotateSel ? annotateBuf1 : annotateBuf0;
122
123 spin_unlock(&annotate_lock); 163 spin_unlock(&annotate_lock);
124 164
125 // Return number of 4-byte words 165 return len;
126 return len / 4;
127} 166}
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)
57 */ 57 */
58static uint32_t cookiemap_exists(uint64_t key) { 58static uint32_t cookiemap_exists(uint64_t key) {
59 unsigned long x, flags, retval = 0; 59 unsigned long x, flags, retval = 0;
60 int cpu = raw_smp_processor_id(); 60 int cpu = smp_processor_id();
61 uint32_t cookiecode = cookiemap_code(key); 61 uint32_t cookiecode = cookiemap_code(key);
62 uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]); 62 uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]);
63 uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]); 63 uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]);
@@ -88,7 +88,7 @@ static uint32_t cookiemap_exists(uint64_t key) {
88 * Post: [v][0][1][2]..[n-2] 88 * Post: [v][0][1][2]..[n-2]
89 */ 89 */
90static void cookiemap_add(uint64_t key, uint32_t value) { 90static void cookiemap_add(uint64_t key, uint32_t value) {
91 int cpu = raw_smp_processor_id(); 91 int cpu = smp_processor_id();
92 int cookiecode = cookiemap_code(key); 92 int cookiecode = cookiemap_code(key);
93 uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]); 93 uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]);
94 uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]); 94 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 @@
1#!/bin/sh
2
3EVENTS=`grep gator_events_init *.c | sed 's/.\+gator_events_init(\(.\+\)).\+/\1/'`
4
5(
6 echo /\* This file is auto generated \*/
7 echo
8 for EVENT in $EVENTS; do
9 echo __weak int $EVENT\(void\)\;
10 done
11 echo
12 echo static int \(*gator_events_list[]\)\(void\) = {
13 for EVENT in $EVENTS; do
14 echo \ $EVENT,
15 done
16 echo }\;
17) > $1.tmp
18
19cmp -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 @@
8 8
9#include "gator.h" 9#include "gator.h"
10 10
11#if defined(__arm__)
12
13#define ARM1136 0xb36 11#define ARM1136 0xb36
14#define ARM1156 0xb56 12#define ARM1156 0xb56
15#define ARM1176 0xb76 13#define ARM1176 0xb76
16 14
17static const char *pmnc_name; 15static const char *pmnc_name;
18 16
19extern u32 gator_cpuid(void);
20
21/* 17/*
22 * Per-CPU PMCR 18 * Per-CPU PMCR
23 */ 19 */
@@ -99,20 +95,6 @@ int gator_events_armv6_create_files(struct super_block *sb, struct dentry *root)
99 return 0; 95 return 0;
100} 96}
101 97
102static int gator_events_armv6_init(int *key)
103{
104 unsigned int cnt;
105
106 for (cnt = PMN0; cnt <= CCNT; cnt++) {
107 pmnc_enabled[cnt] = 0;
108 pmnc_event[cnt] = 0;
109 pmnc_key[cnt] = *key;
110 *key = *key + 1;
111 }
112
113 return 0;
114}
115
116static void gator_events_armv6_online(void) 98static void gator_events_armv6_online(void)
117{ 99{
118 unsigned int cnt; 100 unsigned int cnt;
@@ -130,7 +112,7 @@ static void gator_events_armv6_online(void)
130 for (pmnc = 0, cnt = PMN0; cnt <= CCNT; cnt++) { 112 for (pmnc = 0, cnt = PMN0; cnt <= CCNT; cnt++) {
131 unsigned long event; 113 unsigned long event;
132 114
133 per_cpu(perfPrev, raw_smp_processor_id())[cnt] = 0; 115 per_cpu(perfPrev, smp_processor_id())[cnt] = 0;
134 116
135 if (!pmnc_enabled[cnt]) 117 if (!pmnc_enabled[cnt])
136 continue; 118 continue;
@@ -177,7 +159,7 @@ static void gator_events_armv6_stop(void)
177static int gator_events_armv6_read(int **buffer) 159static int gator_events_armv6_read(int **buffer)
178{ 160{
179 int cnt, len = 0; 161 int cnt, len = 0;
180 int cpu = raw_smp_processor_id(); 162 int cpu = smp_processor_id();
181 163
182 for (cnt = PMN0; cnt <= CCNT; cnt++) { 164 for (cnt = PMN0; cnt <= CCNT; cnt++) {
183 if (pmnc_enabled[cnt]) { 165 if (pmnc_enabled[cnt]) {
@@ -208,10 +190,19 @@ static int gator_events_armv6_read(int **buffer)
208 190
209 return len; 191 return len;
210} 192}
211#endif
212 193
213int gator_events_armv6_install(gator_interface *gi) { 194static struct gator_interface gator_events_armv6_interface = {
214#if defined(__arm__) 195 .create_files = gator_events_armv6_create_files,
196 .stop = gator_events_armv6_stop,
197 .online = gator_events_armv6_online,
198 .offline = gator_events_armv6_offline,
199 .read = gator_events_armv6_read,
200};
201
202int gator_events_armv6_init(void)
203{
204 unsigned int cnt;
205
215 switch (gator_cpuid()) { 206 switch (gator_cpuid()) {
216 case ARM1136: 207 case ARM1136:
217 case ARM1156: 208 case ARM1156:
@@ -222,12 +213,12 @@ int gator_events_armv6_install(gator_interface *gi) {
222 return -1; 213 return -1;
223 } 214 }
224 215
225 gi->create_files = gator_events_armv6_create_files; 216 for (cnt = PMN0; cnt <= CCNT; cnt++) {
226 gi->init = gator_events_armv6_init; 217 pmnc_enabled[cnt] = 0;
227 gi->stop = gator_events_armv6_stop; 218 pmnc_event[cnt] = 0;
228 gi->online = gator_events_armv6_online; 219 pmnc_key[cnt] = gator_events_get_key();
229 gi->offline = gator_events_armv6_offline; 220 }
230 gi->read = gator_events_armv6_read; 221
231#endif 222 return gator_events_install(&gator_events_armv6_interface);
232 return 0;
233} 223}
224gator_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 @@
8 8
9#include "gator.h" 9#include "gator.h"
10 10
11#if defined(__arm__) 11#define CORTEX_A5 0xc05
12
13#define CORTEX_A8 0xc08 12#define CORTEX_A8 0xc08
14#define CORTEX_A9 0xc09 13#define CORTEX_A9 0xc09
14#define CORTEX_A15 0xc0f
15 15
16static const char *pmnc_name; 16static const char *pmnc_name;
17static int pmnc_count; 17static int pmnc_count;
18 18
19extern u32 gator_cpuid(void); 19// Per-CPU PMNC: config reg
20
21/*
22 * Per-CPU PMNC: config reg
23 */
24#define PMNC_E (1 << 0) /* Enable all counters */ 20#define PMNC_E (1 << 0) /* Enable all counters */
25#define PMNC_P (1 << 1) /* Reset all counters */ 21#define PMNC_P (1 << 1) /* Reset all counters */
26#define PMNC_C (1 << 2) /* Cycle counter reset */ 22#define PMNC_C (1 << 2) /* Cycle counter reset */
27#define PMNC_D (1 << 3) /* CCNT counts every 64th cpu cycle */
28#define PMNC_X (1 << 4) /* Export to ETM */
29#define PMNC_DP (1 << 5) /* Disable CCNT if non-invasive debug*/
30#define PMNC_MASK 0x3f /* Mask for writable bits */ 23#define PMNC_MASK 0x3f /* Mask for writable bits */
31 24
32/* 25// ccnt reg
33 * CNTENS: counters enable reg 26#define CCNT_REG (1 << 31)
34 */
35#define CNTENS_P0 (1 << 0)
36#define CNTENS_P1 (1 << 1)
37#define CNTENS_P2 (1 << 2)
38#define CNTENS_P3 (1 << 3)
39#define CNTENS_C (1 << 31)
40#define CNTENS_MASK 0x8000000f /* Mask for writable bits */
41
42/*
43 * CNTENC: counters disable reg
44 */
45#define CNTENC_P0 (1 << 0)
46#define CNTENC_P1 (1 << 1)
47#define CNTENC_P2 (1 << 2)
48#define CNTENC_P3 (1 << 3)
49#define CNTENC_C (1 << 31)
50#define CNTENC_MASK 0x8000000f /* Mask for writable bits */
51
52/*
53 * INTENS: counters overflow interrupt enable reg
54 */
55#define INTENS_P0 (1 << 0)
56#define INTENS_P1 (1 << 1)
57#define INTENS_P2 (1 << 2)
58#define INTENS_P3 (1 << 3)
59#define INTENS_C (1 << 31)
60#define INTENS_MASK 0x8000000f /* Mask for writable bits */
61
62/*
63 * EVTSEL: Event selection reg
64 */
65#define EVTSEL_MASK 0x7f /* Mask for writable bits */
66
67/*
68 * SELECT: Counter selection reg
69 */
70#define SELECT_MASK 0x1f /* Mask for writable bits */
71
72/*
73 * FLAG: counters overflow flag status reg
74 */
75#define FLAG_P0 (1 << 0)
76#define FLAG_P1 (1 << 1)
77#define FLAG_P2 (1 << 2)
78#define FLAG_P3 (1 << 3)
79#define FLAG_C (1 << 31)
80#define FLAG_MASK 0x8000000f /* Mask for writable bits */
81 27
82#define CCNT 0 28#define CCNT 0
83#define CNT0 1 29#define CNT0 1
@@ -105,15 +51,31 @@ static inline u32 armv7_pmnc_read(void)
105 51
106static inline u32 armv7_ccnt_read(void) 52static inline u32 armv7_ccnt_read(void)
107{ 53{
54 u32 zero = 0;
55 u32 den = CCNT_REG;
108 u32 val; 56 u32 val;
109 asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); 57
58 asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); // disable
59 asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); // read
60 asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (zero)); // zero
61 asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); // enable
62
110 return val; 63 return val;
111} 64}
112 65
113static inline u32 armv7_cntn_read(void) 66static inline u32 armv7_cntn_read(unsigned int cnt)
114{ 67{
68 u32 zero = 0;
69 u32 sel = (cnt - CNT0);
70 u32 den = 1 << sel;
115 u32 val; 71 u32 val;
116 asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val)); 72
73 asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); // disable
74 asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (sel)); // select
75 asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val)); // read
76 asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (zero)); // zero
77 asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); // enable
78
117 return val; 79 return val;
118} 80}
119 81
@@ -127,11 +89,10 @@ static inline u32 armv7_pmnc_enable_counter(unsigned int cnt)
127 } 89 }
128 90
129 if (cnt == CCNT) 91 if (cnt == CCNT)
130 val = CNTENS_C; 92 val = CCNT_REG;
131 else 93 else
132 val = (1 << (cnt - CNT0)); 94 val = (1 << (cnt - CNT0));
133 95
134 val &= CNTENS_MASK;
135 asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val)); 96 asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
136 97
137 return cnt; 98 return cnt;
@@ -147,50 +108,15 @@ static inline u32 armv7_pmnc_disable_counter(unsigned int cnt)
147 } 108 }
148 109
149 if (cnt == CCNT) 110 if (cnt == CCNT)
150 val = CNTENC_C; 111 val = CCNT_REG;
151 else 112 else
152 val = (1 << (cnt - CNT0)); 113 val = (1 << (cnt - CNT0));
153 114
154 val &= CNTENC_MASK;
155 asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val)); 115 asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
156 116
157 return cnt; 117 return cnt;
158} 118}
159 119
160static inline u32 armv7_pmnc_enable_intens(unsigned int cnt)
161{
162 u32 val;
163
164 if (cnt >= CNTMAX) {
165 pr_err("gator: CPU%u enabling wrong PMNC counter interrupt enable %d\n", smp_processor_id(), cnt);
166 return -1;
167 }
168
169 if (cnt == CCNT)
170 val = INTENS_C;
171 else
172 val = (1 << (cnt - CNT0));
173
174 val &= INTENS_MASK;
175 asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (val));
176
177 return cnt;
178}
179
180static inline u32 armv7_pmnc_getreset_flags(void)
181{
182 u32 val;
183
184 /* Read */
185 asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val));
186
187 /* Write to clear flags */
188 val &= FLAG_MASK;
189 asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (val));
190
191 return val;
192}
193
194static inline int armv7_pmnc_select_counter(unsigned int cnt) 120static inline int armv7_pmnc_select_counter(unsigned int cnt)
195{ 121{
196 u32 val; 122 u32 val;
@@ -200,7 +126,7 @@ static inline int armv7_pmnc_select_counter(unsigned int cnt)
200 return -1; 126 return -1;
201 } 127 }
202 128
203 val = (cnt - CNT0) & SELECT_MASK; 129 val = (cnt - CNT0);
204 asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val)); 130 asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
205 131
206 return cnt; 132 return cnt;
@@ -209,7 +135,6 @@ static inline int armv7_pmnc_select_counter(unsigned int cnt)
209static inline void armv7_pmnc_write_evtsel(unsigned int cnt, u32 val) 135static inline void armv7_pmnc_write_evtsel(unsigned int cnt, u32 val)
210{ 136{
211 if (armv7_pmnc_select_counter(cnt) == cnt) { 137 if (armv7_pmnc_select_counter(cnt) == cnt) {
212 val &= EVTSEL_MASK;
213 asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val)); 138 asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
214 } 139 }
215} 140}
@@ -265,66 +190,39 @@ static int gator_events_armv7_create_files(struct super_block *sb, struct dentry
265 return 0; 190 return 0;
266} 191}
267 192
268static int gator_events_armv7_init(int *key)
269{
270 unsigned int cnt;
271
272 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
273 pmnc_enabled[cnt] = 0;
274 pmnc_event[cnt] = 0;
275 pmnc_key[cnt] = *key;
276 *key = *key + 1;
277 }
278
279 return 0;
280}
281
282static void gator_events_armv7_online(void) 193static void gator_events_armv7_online(void)
283{ 194{
284 unsigned int cnt; 195 unsigned int cnt;
196 int cpu = smp_processor_id();
285 197
286 if (armv7_pmnc_read() & PMNC_E) { 198 if (armv7_pmnc_read() & PMNC_E) {
287 armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E); 199 armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E);
288 } 200 }
289 201
290 /* Initialize & Reset PMNC: C bit and P bit */ 202 // Initialize & Reset PMNC: C bit and P bit
291 armv7_pmnc_write(PMNC_P | PMNC_C); 203 armv7_pmnc_write(PMNC_P | PMNC_C);
292 204
293 for (cnt = CCNT; cnt < CNTMAX; cnt++) { 205 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
294 unsigned long event; 206 unsigned long event;
295 207
296 per_cpu(perfPrev, raw_smp_processor_id())[cnt] = 0; 208 per_cpu(perfPrev, cpu)[cnt] = 0;
297 209
298 if (!pmnc_enabled[cnt]) 210 if (!pmnc_enabled[cnt])
299 continue; 211 continue;
300 212
301 /* 213 // Disable counter
302 * Disable counter
303 */
304 armv7_pmnc_disable_counter(cnt); 214 armv7_pmnc_disable_counter(cnt);
305 215
306 event = pmnc_event[cnt] & 255; 216 event = pmnc_event[cnt] & 255;
307 217
308 /* 218 // Set event (if destined for PMNx counters), we don't need to set the event if it's a cycle count
309 * Set event (if destined for PMNx counters)
310 * We don't need to set the event if it's a cycle count
311 */
312 if (cnt != CCNT) 219 if (cnt != CCNT)
313 armv7_pmnc_write_evtsel(cnt, event); 220 armv7_pmnc_write_evtsel(cnt, event);
314 221
315 /* 222 // Reset counter
316 * [Do not] Enable interrupt for this counter
317 */
318 /* armv7_pmnc_enable_intens(cnt); */
319
320 /*
321 * Reset counter
322 */
323 armv7_pmnc_reset_counter(cnt); 223 armv7_pmnc_reset_counter(cnt);
324 224
325 /* 225 // Enable counter, but do not enable interrupt for this counter
326 * Enable counter
327 */
328 armv7_pmnc_enable_counter(cnt); 226 armv7_pmnc_enable_counter(cnt);
329 } 227 }
330 228
@@ -350,23 +248,19 @@ static void gator_events_armv7_stop(void)
350static int gator_events_armv7_read(int **buffer) 248static int gator_events_armv7_read(int **buffer)
351{ 249{
352 int cnt, len = 0; 250 int cnt, len = 0;
353 int cpu = raw_smp_processor_id(); 251 int cpu = smp_processor_id();
354 252
355 if (!pmnc_count) 253 if (!pmnc_count)
356 return 0; 254 return 0;
357 255
358 armv7_pmnc_getreset_flags();
359 for (cnt = 0; cnt < pmnc_count; cnt++) { 256 for (cnt = 0; cnt < pmnc_count; cnt++) {
360 if (pmnc_enabled[cnt]) { 257 if (pmnc_enabled[cnt]) {
361 int value; 258 int value;
362 if (cnt == CCNT) { 259 if (cnt == CCNT) {
363 value = armv7_ccnt_read(); 260 value = armv7_ccnt_read();
364 } else if (armv7_pmnc_select_counter(cnt) == cnt) {
365 value = armv7_cntn_read();
366 } else { 261 } else {
367 value = 0; 262 value = armv7_cntn_read(cnt);
368 } 263 }
369 armv7_pmnc_reset_counter(cnt);
370 if (value != per_cpu(perfPrev, cpu)[cnt]) { 264 if (value != per_cpu(perfPrev, cpu)[cnt]) {
371 per_cpu(perfPrev, cpu)[cnt] = value; 265 per_cpu(perfPrev, cpu)[cnt] = value;
372 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt]; 266 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
@@ -381,11 +275,24 @@ static int gator_events_armv7_read(int **buffer)
381 275
382 return len; 276 return len;
383} 277}
384#endif
385 278
386int gator_events_armv7_install(gator_interface *gi) { 279static struct gator_interface gator_events_armv7_interface = {
387#if defined(__arm__) 280 .create_files = gator_events_armv7_create_files,
281 .stop = gator_events_armv7_stop,
282 .online = gator_events_armv7_online,
283 .offline = gator_events_armv7_offline,
284 .read = gator_events_armv7_read,
285};
286
287int gator_events_armv7_init(void)
288{
289 unsigned int cnt;
290
388 switch (gator_cpuid()) { 291 switch (gator_cpuid()) {
292 case CORTEX_A5:
293 pmnc_name = "Cortex-A5";
294 pmnc_count = 2;
295 break;
389 case CORTEX_A8: 296 case CORTEX_A8:
390 pmnc_name = "Cortex-A8"; 297 pmnc_name = "Cortex-A8";
391 pmnc_count = 4; 298 pmnc_count = 4;
@@ -394,18 +301,22 @@ int gator_events_armv7_install(gator_interface *gi) {
394 pmnc_name = "Cortex-A9"; 301 pmnc_name = "Cortex-A9";
395 pmnc_count = 6; 302 pmnc_count = 6;
396 break; 303 break;
304 case CORTEX_A15:
305 pmnc_name = "Cortex-A15";
306 pmnc_count = 6;
307 break;
397 default: 308 default:
398 return -1; 309 return -1;
399 } 310 }
400 311
401 pmnc_count++; // CNT[n] + CCNT 312 pmnc_count++; // CNT[n] + CCNT
402 313
403 gi->create_files = gator_events_armv7_create_files; 314 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
404 gi->init = gator_events_armv7_init; 315 pmnc_enabled[cnt] = 0;
405 gi->stop = gator_events_armv7_stop; 316 pmnc_event[cnt] = 0;
406 gi->online = gator_events_armv7_online; 317 pmnc_key[cnt] = gator_events_get_key();
407 gi->offline = gator_events_armv7_offline; 318 }
408 gi->read = gator_events_armv7_read; 319
409#endif 320 return gator_events_install(&gator_events_armv7_interface);
410 return 0;
411} 321}
322gator_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
33{ 33{
34 unsigned long flags; 34 unsigned long flags;
35 int write, size; 35 int write, size;
36 int cpu = raw_smp_processor_id(); 36 int cpu = smp_processor_id();
37 37
38 if (!rq) 38 if (!rq)
39 return; 39 return;
@@ -79,19 +79,6 @@ static int gator_events_block_create_files(struct super_block *sb, struct dentry
79 return 0; 79 return 0;
80} 80}
81 81
82static int gator_events_block_init(int *key)
83{
84 block_rq_wr_enabled = 0;
85 block_rq_rd_enabled = 0;
86
87 block_rq_wr_key = *key;
88 *key = *key + 1;
89 block_rq_rd_key = *key;
90 *key = *key + 1;
91
92 return 0;
93}
94
95static int gator_events_block_start(void) 82static int gator_events_block_start(void)
96{ 83{
97 int cpu; 84 int cpu;
@@ -128,7 +115,7 @@ static int gator_events_block_read(int **buffer)
128{ 115{
129 unsigned long flags; 116 unsigned long flags;
130 int len, value, cpu, data = 0; 117 int len, value, cpu, data = 0;
131 cpu = raw_smp_processor_id(); 118 cpu = smp_processor_id();
132 119
133 if (per_cpu(new_data_avail, cpu) == false) 120 if (per_cpu(new_data_avail, cpu) == false)
134 return 0; 121 return 0;
@@ -164,11 +151,21 @@ static int gator_events_block_read(int **buffer)
164 return len; 151 return len;
165} 152}
166 153
167int gator_events_block_install(gator_interface *gi) { 154static struct gator_interface gator_events_block_interface = {
168 gi->create_files = gator_events_block_create_files; 155 .create_files = gator_events_block_create_files,
169 gi->init = gator_events_block_init; 156 .start = gator_events_block_start,
170 gi->start = gator_events_block_start; 157 .stop = gator_events_block_stop,
171 gi->stop = gator_events_block_stop; 158 .read = gator_events_block_read,
172 gi->read = gator_events_block_read; 159};
173 return 0; 160
161int gator_events_block_init(void)
162{
163 block_rq_wr_enabled = 0;
164 block_rq_rd_enabled = 0;
165
166 block_rq_wr_key = gator_events_get_key();
167 block_rq_rd_key = gator_events_get_key();
168
169 return gator_events_install(&gator_events_block_interface);
174} 170}
171gator_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,
30 // disable interrupts to synchronize with gator_events_irq_read() 30 // disable interrupts to synchronize with gator_events_irq_read()
31 // spinlocks not needed since percpu buffers are used 31 // spinlocks not needed since percpu buffers are used
32 local_irq_save(flags); 32 local_irq_save(flags);
33 per_cpu(irqCnt, raw_smp_processor_id())[HARDIRQ]++; 33 per_cpu(irqCnt, smp_processor_id())[HARDIRQ]++;
34 local_irq_restore(flags); 34 local_irq_restore(flags);
35} 35}
36 36
@@ -45,7 +45,7 @@ GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(unsigned int vec_nr))
45 // disable interrupts to synchronize with gator_events_irq_read() 45 // disable interrupts to synchronize with gator_events_irq_read()
46 // spinlocks not needed since percpu buffers are used 46 // spinlocks not needed since percpu buffers are used
47 local_irq_save(flags); 47 local_irq_save(flags);
48 per_cpu(irqCnt, raw_smp_processor_id())[SOFTIRQ]++; 48 per_cpu(irqCnt, smp_processor_id())[SOFTIRQ]++;
49 local_irq_restore(flags); 49 local_irq_restore(flags);
50} 50}
51 51
@@ -72,19 +72,6 @@ static int gator_events_irq_create_files(struct super_block *sb, struct dentry *
72 return 0; 72 return 0;
73} 73}
74 74
75static int gator_events_irq_init(int *key)
76{
77 hardirq_key = *key;
78 *key = *key + 1;
79 softirq_key = *key;
80 *key = *key + 1;
81
82 hardirq_enabled = 0;
83 softirq_enabled = 0;
84
85 return 0;
86}
87
88static int gator_events_irq_start(void) 75static int gator_events_irq_start(void)
89{ 76{
90 int cpu, i; 77 int cpu, i;
@@ -131,7 +118,7 @@ static int gator_events_irq_read(int **buffer)
131{ 118{
132 unsigned long flags; 119 unsigned long flags;
133 int len, value; 120 int len, value;
134 int cpu = raw_smp_processor_id(); 121 int cpu = smp_processor_id();
135 122
136 len = 0; 123 len = 0;
137 if (hardirq_enabled) { 124 if (hardirq_enabled) {
@@ -164,11 +151,21 @@ static int gator_events_irq_read(int **buffer)
164 return len; 151 return len;
165} 152}
166 153
167int gator_events_irq_install(gator_interface *gi) { 154static struct gator_interface gator_events_irq_interface = {
168 gi->create_files = gator_events_irq_create_files; 155 .create_files = gator_events_irq_create_files,
169 gi->init = gator_events_irq_init; 156 .start = gator_events_irq_start,
170 gi->start = gator_events_irq_start; 157 .stop = gator_events_irq_stop,
171 gi->stop = gator_events_irq_stop; 158 .read = gator_events_irq_read,
172 gi->read = gator_events_irq_read; 159};
173 return 0; 160
161int gator_events_irq_init(void)
162{
163 hardirq_key = gator_events_get_key();
164 softirq_key = gator_events_get_key();
165
166 hardirq_enabled = 0;
167 softirq_enabled = 0;
168
169 return gator_events_install(&gator_events_irq_interface);
174} 170}
171gator_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
69 return 0; 69 return 0;
70} 70}
71 71
72static int gator_events_meminfo_init(int *key)
73{
74 int i;
75
76 meminfo_global_enabled = 0;
77 for (i = 0; i < MEMINFO_TOTAL; i++) {
78 meminfo_enabled[i] = 0;
79 meminfo_key[i] = *key;
80 *key = *key + 1;
81 }
82
83 return 0;
84}
85
86static int gator_events_meminfo_start(void) 72static int gator_events_meminfo_start(void)
87{ 73{
88 int i; 74 int i;
@@ -187,11 +173,23 @@ static int gator_events_meminfo_read(int **buffer)
187 return meminfo_length; 173 return meminfo_length;
188} 174}
189 175
190int gator_events_meminfo_install(gator_interface *gi) { 176static struct gator_interface gator_events_meminfo_interface = {
191 gi->create_files = gator_events_meminfo_create_files; 177 .create_files = gator_events_meminfo_create_files,
192 gi->init = gator_events_meminfo_init; 178 .start = gator_events_meminfo_start,
193 gi->start = gator_events_meminfo_start; 179 .stop = gator_events_meminfo_stop,
194 gi->stop = gator_events_meminfo_stop; 180 .read = gator_events_meminfo_read,
195 gi->read = gator_events_meminfo_read; 181};
196 return 0; 182
183int gator_events_meminfo_init(void)
184{
185 int i;
186
187 meminfo_global_enabled = 0;
188 for (i = 0; i < MEMINFO_TOTAL; i++) {
189 meminfo_enabled[i] = 0;
190 meminfo_key[i] = gator_events_get_key();
191 }
192
193 return gator_events_install(&gator_events_meminfo_interface);
197} 194}
195gator_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 @@
1/*
2 * Example events provider
3 *
4 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * Similar entires must be present in events.xml file:
11 *
12 * <counter_set name="mmaped_cntX">
13 * <counter name="mmaped_cnt0"/>
14 * <counter name="mmaped_cnt1"/>
15 * </counter_set>
16 * <category name="mmaped" counter_set="mmaped_cntX" per_cpu="no">
17 * <event event="0x0" title="Simulated" name="Sine" description="Sort-of-sine"/>
18 * <event event="0x1" title="Simulated" name="Triangle" description="Triangular wave"/>
19 * <event event="0x2" title="Simulated" name="PWM" description="PWM Signal"/>
20 * </category>
21 */
22
23#include <linux/init.h>
24#include <linux/io.h>
25#include <linux/ratelimit.h>
26
27#include "gator.h"
28
29#define MMAPED_COUNTERS_NUM 3
30
31static struct {
32 unsigned long enabled;
33 unsigned long event;
34 unsigned long key;
35} mmaped_counters[MMAPED_COUNTERS_NUM];
36
37static int mmaped_buffer[MMAPED_COUNTERS_NUM * 2];
38
39#ifdef TODO
40static void __iomem *mmaped_base;
41#endif
42
43/* Adds mmaped_cntX directories and enabled, event, and key files to /dev/gator/events */
44static int gator_events_mmaped_create_files(struct super_block *sb,
45 struct dentry *root)
46{
47 int i;
48
49 for (i = 0; i < MMAPED_COUNTERS_NUM; i++) {
50 char buf[16];
51 struct dentry *dir;
52
53 snprintf(buf, sizeof(buf), "mmaped_cnt%d", i);
54 dir = gatorfs_mkdir(sb, root, buf);
55 if (WARN_ON(!dir))
56 return -1;
57 gatorfs_create_ulong(sb, dir, "enabled",
58 &mmaped_counters[i].enabled);
59 gatorfs_create_ulong(sb, dir, "event",
60 &mmaped_counters[i].event);
61 gatorfs_create_ro_ulong(sb, dir, "key",
62 &mmaped_counters[i].key);
63 }
64
65 return 0;
66}
67
68static int gator_events_mmaped_start(void)
69{
70#ifdef TODO
71 for (i = 0; i < MMAPED_COUNTERS_NUM; i++)
72 writel(mmaped_counters[i].event,
73 mmaped_base + COUNTERS_CONFIG_OFFSET[i]);
74
75 writel(ENABLED, COUNTERS_CONTROL_OFFSET);
76#endif
77
78 return 0;
79}
80
81static void gator_events_mmaped_stop(void)
82{
83#ifdef TODO
84 writel(DISABLED, COUNTERS_CONTROL_OFFSET);
85#endif
86}
87
88#ifndef TODO
89/* This function "simulates" counters, generating values of fancy
90 * functions like sine or triangle... */
91static int mmaped_simulate(int counter)
92{
93 int result = 0;
94
95 switch (counter) {
96 case 0: /* sort-of-sine */
97 {
98 static int t;
99 int x;
100
101 if (t % 1024 < 512)
102 x = 512 - (t % 512);
103 else
104 x = t % 512;
105
106 result = 32 * x / 512;
107 result = result * result;
108
109 if (t < 1024)
110 result = 1922 - result;
111
112 t = (t + 1) % 2048;
113 }
114 break;
115 case 1: /* triangle */
116 {
117 static int v, d = 1;
118
119 v += d;
120 if (v % 2000 == 0)
121 d = -d;
122
123 result = v;
124 }
125 break;
126 case 2: /* PWM signal */
127 {
128 static int t, dc;
129
130 t = (t + 1) % 2000;
131 if (t % 100)
132 dc = (dc + 200) % 2000;
133
134 result = t < dc ? 0 : 2000;
135 }
136 break;
137 }
138
139 return result;
140}
141#endif
142
143static int gator_events_mmaped_read(int **buffer)
144{
145 int i;
146 int len = 0;
147
148 /* System wide counters - read from one core only */
149 if (smp_processor_id())
150 return 0;
151
152 for (i = 0; i < MMAPED_COUNTERS_NUM; i++) {
153 if (mmaped_counters[i].enabled) {
154 mmaped_buffer[len++] = mmaped_counters[i].key;
155#ifdef TODO
156 mmaped_buffer[len++] = readl(mmaped_base +
157 COUNTERS_VALUE_OFFSET[i]);
158#else
159 mmaped_buffer[len++] = mmaped_simulate(
160 mmaped_counters[i].event);
161#endif
162 }
163 }
164
165 if (buffer)
166 *buffer = mmaped_buffer;
167
168 return len;
169}
170
171static struct gator_interface gator_events_mmaped_interface = {
172 .create_files = gator_events_mmaped_create_files,
173 .start = gator_events_mmaped_start,
174 .stop = gator_events_mmaped_stop,
175 .read = gator_events_mmaped_read,
176};
177
178/* Must not be static! */
179int __init gator_events_mmaped_init(void)
180{
181 int i;
182
183#ifdef TODO
184 mmaped_base = ioremap(COUNTERS_PHYS_ADDR, SZ_4K);
185 if (!mmaped_base)
186 return -ENOMEM;
187#endif
188
189 for (i = 0; i < MMAPED_COUNTERS_NUM; i++) {
190 mmaped_counters[i].enabled = 0;
191 mmaped_counters[i].key = gator_events_get_key();
192 }
193
194 return gator_events_install(&gator_events_mmaped_interface);
195}
196gator_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 *
101 return 0; 101 return 0;
102} 102}
103 103
104static int gator_events_net_init(int *key)
105{
106 netdrv_key = *key;
107 *key = *key + 1;
108 netrx_key = *key;
109 *key = *key + 1;
110 nettx_key = *key;
111 *key = *key + 1;
112
113 netdrv_enabled = 0;
114 netrx_enabled = 0;
115 nettx_enabled = 0;
116
117 return 0;
118}
119
120static int gator_events_net_start(void) 104static int gator_events_net_start(void)
121{ 105{
122 get_network_stats(NULL); 106 get_network_stats(NULL);
@@ -138,7 +122,7 @@ static int gator_events_net_read(int **buffer)
138 int len, drv_delta, rx_delta, tx_delta; 122 int len, drv_delta, rx_delta, tx_delta;
139 static int last_drv_delta = 0, last_rx_delta = 0, last_tx_delta = 0; 123 static int last_drv_delta = 0, last_rx_delta = 0, last_tx_delta = 0;
140 124
141 if (raw_smp_processor_id() != 0) 125 if (smp_processor_id() != 0)
142 return 0; 126 return 0;
143 127
144 schedule_work(&wq_get_stats); 128 schedule_work(&wq_get_stats);
@@ -169,12 +153,25 @@ static int gator_events_net_read(int **buffer)
169 return len; 153 return len;
170} 154}
171 155
172int gator_events_net_install(gator_interface *gi) { 156static struct gator_interface gator_events_net_interface = {
173 gi->create_files = gator_events_net_create_files; 157 .create_files = gator_events_net_create_files,
174 gi->init = gator_events_net_init; 158 .start = gator_events_net_start,
175 gi->start = gator_events_net_start; 159 .stop = gator_events_net_stop,
176 gi->stop = gator_events_net_stop; 160 .read = gator_events_net_read,
177 gi->read = gator_events_net_read; 161};
162
163int gator_events_net_init(void)
164{
178 gator_net_traffic++; 165 gator_net_traffic++;
179 return 0; 166
167 netdrv_key = gator_events_get_key();
168 netrx_key = gator_events_get_key();
169 nettx_key = gator_events_get_key();
170
171 netdrv_enabled = 0;
172 netrx_enabled = 0;
173 nettx_enabled = 0;
174
175 return gator_events_install(&gator_events_net_interface);
180} 176}
177gator_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 @@
1/**
2 * PL310 (L2 Cache Controller) event counters for gator
3 *
4 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/init.h>
12#include <linux/io.h>
13#include <asm/hardware/cache-l2x0.h>
14
15#include "gator.h"
16
17#define PL310_COUNTERS_NUM 2
18
19static struct {
20 unsigned long enabled;
21 unsigned long event;
22 unsigned long key;
23} pl310_counters[PL310_COUNTERS_NUM];
24
25static int pl310_buffer[PL310_COUNTERS_NUM * 2];
26
27static void __iomem *pl310_base;
28
29
30
31static void gator_events_pl310_reset_counters(void)
32{
33 u32 val = readl(pl310_base + L2X0_EVENT_CNT_CTRL);
34
35 val |= ((1 << PL310_COUNTERS_NUM) - 1) << 1;
36
37 writel(val, pl310_base + L2X0_EVENT_CNT_CTRL);
38}
39
40
41static int gator_events_pl310_create_files(struct super_block *sb,
42 struct dentry *root)
43{
44 int i;
45
46 for (i = 0; i < PL310_COUNTERS_NUM; i++) {
47 char buf[16];
48 struct dentry *dir;
49
50 snprintf(buf, sizeof(buf), "PL310_cnt%d", i);
51 dir = gatorfs_mkdir(sb, root, buf);
52 if (WARN_ON(!dir))
53 return -1;
54 gatorfs_create_ulong(sb, dir, "enabled",
55 &pl310_counters[i].enabled);
56 gatorfs_create_ulong(sb, dir, "event",
57 &pl310_counters[i].event);
58 gatorfs_create_ro_ulong(sb, dir, "key",
59 &pl310_counters[i].key);
60 }
61
62 return 0;
63}
64
65static int gator_events_pl310_start(void)
66{
67 static const unsigned long l2x0_event_cntx_cfg[PL310_COUNTERS_NUM] = {
68 L2X0_EVENT_CNT0_CFG,
69 L2X0_EVENT_CNT1_CFG,
70 };
71 int i;
72
73 /* Counter event sources */
74 for (i = 0; i < PL310_COUNTERS_NUM; i++)
75 writel((pl310_counters[i].event & 0xf) << 2,
76 pl310_base + l2x0_event_cntx_cfg[i]);
77
78 gator_events_pl310_reset_counters();
79
80 /* Event counter enable */
81 writel(1, pl310_base + L2X0_EVENT_CNT_CTRL);
82
83 return 0;
84}
85
86static void gator_events_pl310_stop(void)
87{
88 /* Event counter disable */
89 writel(0, pl310_base + L2X0_EVENT_CNT_CTRL);
90}
91
92static int gator_events_pl310_read(int **buffer)
93{
94 static const unsigned long l2x0_event_cntx_val[PL310_COUNTERS_NUM] = {
95 L2X0_EVENT_CNT0_VAL,
96 L2X0_EVENT_CNT1_VAL,
97 };
98 int i;
99 int len = 0;
100
101 if (smp_processor_id())
102 return 0;
103
104 for (i = 0; i < PL310_COUNTERS_NUM; i++) {
105 if (pl310_counters[i].enabled) {
106 pl310_buffer[len++] = pl310_counters[i].key;
107 pl310_buffer[len++] = readl(pl310_base +
108 l2x0_event_cntx_val[i]);
109 }
110 }
111
112 /* PL310 counters are saturating, not wrapping in case of overflow */
113 gator_events_pl310_reset_counters();
114
115 if (buffer)
116 *buffer = pl310_buffer;
117
118 return len;
119}
120
121static struct gator_interface gator_events_pl310_interface = {
122 .create_files = gator_events_pl310_create_files,
123 .start = gator_events_pl310_start,
124 .stop = gator_events_pl310_stop,
125 .read = gator_events_pl310_read,
126};
127
128static void __maybe_unused gator_events_pl310_probe(unsigned long phys)
129{
130 if (pl310_base)
131 return;
132
133 pl310_base = ioremap(phys, SZ_4K);
134 if (pl310_base) {
135 u32 cache_id = readl(pl310_base + L2X0_CACHE_ID);
136
137 if ((cache_id & 0xff0003c0) != 0x410000c0) {
138 iounmap(pl310_base);
139 pl310_base = NULL;
140 }
141 }
142}
143
144int gator_events_pl310_init(void)
145{
146 int i;
147
148#if defined(CONFIG_ARCH_EXYNOS4)
149 gator_events_pl310_probe(0xfe600000);
150#endif
151#if defined(CONFIG_ARCH_OMAP4)
152 gator_events_pl310_probe(0x48242000);
153#endif
154#if defined(CONFIG_ARCH_TEGRA)
155 gator_events_pl310_probe(0x50043000);
156#endif
157#if defined(CONFIG_ARCH_U8500)
158 gator_events_pl310_probe(0xa0412000);
159#endif
160#if defined(CONFIG_ARCH_VEXPRESS) && !defined(CONFIG_ARCH_VEXPRESS_CA15X4)
161 // A9x4 core tile (HBI-0191)
162 gator_events_pl310_probe(0x1e00a000);
163 // New memory map tiles
164 gator_events_pl310_probe(0x2c0f0000);
165#endif
166 if (!pl310_base)
167 return -1;
168
169 for (i = 0; i < PL310_COUNTERS_NUM; i++) {
170 pl310_counters[i].enabled = 0;
171 pl310_counters[i].key = gator_events_get_key();
172 }
173
174 return gator_events_install(&gator_events_pl310_interface);
175}
176gator_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_
29 // disable interrupts to synchronize with gator_events_sched_read() 29 // disable interrupts to synchronize with gator_events_sched_read()
30 // spinlocks not needed since percpu buffers are used 30 // spinlocks not needed since percpu buffers are used
31 local_irq_save(flags); 31 local_irq_save(flags);
32 per_cpu(schedCnt, raw_smp_processor_id())[SCHED_SWITCH]++; 32 per_cpu(schedCnt, smp_processor_id())[SCHED_SWITCH]++;
33 local_irq_restore(flags); 33 local_irq_restore(flags);
34} 34}
35 35
@@ -48,16 +48,6 @@ static int gator_events_sched_create_files(struct super_block *sb, struct dentry
48 return 0; 48 return 0;
49} 49}
50 50
51static int gator_events_sched_init(int *key)
52{
53 sched_switch_enabled = 0;
54
55 sched_switch_key = *key;
56 *key = *key + 1;
57
58 return 0;
59}
60
61static int gator_events_sched_start(void) 51static int gator_events_sched_start(void)
62{ 52{
63 // register tracepoints 53 // register tracepoints
@@ -88,7 +78,7 @@ static int gator_events_sched_read(int **buffer)
88{ 78{
89 unsigned long flags; 79 unsigned long flags;
90 int len, value; 80 int len, value;
91 int cpu = raw_smp_processor_id(); 81 int cpu = smp_processor_id();
92 82
93 len = 0; 83 len = 0;
94 if (sched_switch_enabled) { 84 if (sched_switch_enabled) {
@@ -106,11 +96,19 @@ static int gator_events_sched_read(int **buffer)
106 return len; 96 return len;
107} 97}
108 98
109int gator_events_sched_install(gator_interface *gi) { 99static struct gator_interface gator_events_sched_interface = {
110 gi->create_files = gator_events_sched_create_files; 100 .create_files = gator_events_sched_create_files,
111 gi->init = gator_events_sched_init; 101 .start = gator_events_sched_start,
112 gi->start = gator_events_sched_start; 102 .stop = gator_events_sched_stop,
113 gi->stop = gator_events_sched_stop; 103 .read = gator_events_sched_read,
114 gi->read = gator_events_sched_read; 104};
115 return 0; 105
106int gator_events_sched_init(void)
107{
108 sched_switch_enabled = 0;
109
110 sched_switch_key = gator_events_get_key();
111
112 return gator_events_install(&gator_events_sched_interface);
116} 113}
114gator_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 @@
1/**
2 * Copyright (C) ARM Limited 2011. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "gator.h"
10
11#define SCORPION 0xf
12#define SCORPIONMP 0x2d
13
14static const char *pmnc_name;
15static int pmnc_count;
16
17// Per-CPU PMNC: config reg
18#define PMNC_E (1 << 0) /* Enable all counters */
19#define PMNC_P (1 << 1) /* Reset all counters */
20#define PMNC_C (1 << 2) /* Cycle counter reset */
21#define PMNC_D (1 << 3) /* CCNT counts every 64th cpu cycle */
22#define PMNC_X (1 << 4) /* Export to ETM */
23#define PMNC_DP (1 << 5) /* Disable CCNT if non-invasive debug*/
24#define PMNC_MASK 0x3f /* Mask for writable bits */
25
26// ccnt reg
27#define CCNT_REG (1 << 31)
28
29#define CCNT 0
30#define CNT0 1
31#define CNTMAX (4+1)
32
33static unsigned long pmnc_enabled[CNTMAX];
34static unsigned long pmnc_event[CNTMAX];
35static unsigned long pmnc_key[CNTMAX];
36
37static DEFINE_PER_CPU(int[CNTMAX], perfPrev);
38static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
39
40enum scorpion_perf_types {
41 SCORPION_ICACHE_EXPL_INV = 0x4c,
42 SCORPION_ICACHE_MISS = 0x4d,
43 SCORPION_ICACHE_ACCESS = 0x4e,
44 SCORPION_ICACHE_CACHEREQ_L2 = 0x4f,
45 SCORPION_ICACHE_NOCACHE_L2 = 0x50,
46 SCORPION_HIQUP_NOPED = 0x51,
47 SCORPION_DATA_ABORT = 0x52,
48 SCORPION_IRQ = 0x53,
49 SCORPION_FIQ = 0x54,
50 SCORPION_ALL_EXCPT = 0x55,
51 SCORPION_UNDEF = 0x56,
52 SCORPION_SVC = 0x57,
53 SCORPION_SMC = 0x58,
54 SCORPION_PREFETCH_ABORT = 0x59,
55 SCORPION_INDEX_CHECK = 0x5a,
56 SCORPION_NULL_CHECK = 0x5b,
57 SCORPION_EXPL_ICIALLU = 0x5c,
58 SCORPION_IMPL_ICIALLU = 0x5d,
59 SCORPION_NONICIALLU_BTAC_INV = 0x5e,
60 SCORPION_ICIMVAU_IMPL_ICIALLU = 0x5f,
61 SCORPION_SPIPE_ONLY_CYCLES = 0x60,
62 SCORPION_XPIPE_ONLY_CYCLES = 0x61,
63 SCORPION_DUAL_CYCLES = 0x62,
64 SCORPION_DISPATCH_ANY_CYCLES = 0x63,
65 SCORPION_FIFO_FULLBLK_CMT = 0x64,
66 SCORPION_FAIL_COND_INST = 0x65,
67 SCORPION_PASS_COND_INST = 0x66,
68 SCORPION_ALLOW_VU_CLK = 0x67,
69 SCORPION_VU_IDLE = 0x68,
70 SCORPION_ALLOW_L2_CLK = 0x69,
71 SCORPION_L2_IDLE = 0x6a,
72 SCORPION_DTLB_IMPL_INV_SCTLR_DACR = 0x6b,
73 SCORPION_DTLB_EXPL_INV = 0x6c,
74 SCORPION_DTLB_MISS = 0x6d,
75 SCORPION_DTLB_ACCESS = 0x6e,
76 SCORPION_ITLB_MISS = 0x6f,
77 SCORPION_ITLB_IMPL_INV = 0x70,
78 SCORPION_ITLB_EXPL_INV = 0x71,
79 SCORPION_UTLB_D_MISS = 0x72,
80 SCORPION_UTLB_D_ACCESS = 0x73,
81 SCORPION_UTLB_I_MISS = 0x74,
82 SCORPION_UTLB_I_ACCESS = 0x75,
83 SCORPION_UTLB_INV_ASID = 0x76,
84 SCORPION_UTLB_INV_MVA = 0x77,
85 SCORPION_UTLB_INV_ALL = 0x78,
86 SCORPION_S2_HOLD_RDQ_UNAVAIL = 0x79,
87 SCORPION_S2_HOLD = 0x7a,
88 SCORPION_S2_HOLD_DEV_OP = 0x7b,
89 SCORPION_S2_HOLD_ORDER = 0x7c,
90 SCORPION_S2_HOLD_BARRIER = 0x7d,
91 SCORPION_VIU_DUAL_CYCLE = 0x7e,
92 SCORPION_VIU_SINGLE_CYCLE = 0x7f,
93 SCORPION_VX_PIPE_WAR_STALL_CYCLES = 0x80,
94 SCORPION_VX_PIPE_WAW_STALL_CYCLES = 0x81,
95 SCORPION_VX_PIPE_RAW_STALL_CYCLES = 0x82,
96 SCORPION_VX_PIPE_LOAD_USE_STALL = 0x83,
97 SCORPION_VS_PIPE_WAR_STALL_CYCLES = 0x84,
98 SCORPION_VS_PIPE_WAW_STALL_CYCLES = 0x85,
99 SCORPION_VS_PIPE_RAW_STALL_CYCLES = 0x86,
100 SCORPION_EXCEPTIONS_INV_OPERATION = 0x87,
101 SCORPION_EXCEPTIONS_DIV_BY_ZERO = 0x88,
102 SCORPION_COND_INST_FAIL_VX_PIPE = 0x89,
103 SCORPION_COND_INST_FAIL_VS_PIPE = 0x8a,
104 SCORPION_EXCEPTIONS_OVERFLOW = 0x8b,
105 SCORPION_EXCEPTIONS_UNDERFLOW = 0x8c,
106 SCORPION_EXCEPTIONS_DENORM = 0x8d,
107#ifdef CONFIG_ARCH_MSM_SCORPIONMP
108 SCORPIONMP_NUM_BARRIERS = 0x8e,
109 SCORPIONMP_BARRIER_CYCLES = 0x8f,
110#else
111 SCORPION_BANK_AB_HIT = 0x8e,
112 SCORPION_BANK_AB_ACCESS = 0x8f,
113 SCORPION_BANK_CD_HIT = 0x90,
114 SCORPION_BANK_CD_ACCESS = 0x91,
115 SCORPION_BANK_AB_DSIDE_HIT = 0x92,
116 SCORPION_BANK_AB_DSIDE_ACCESS = 0x93,
117 SCORPION_BANK_CD_DSIDE_HIT = 0x94,
118 SCORPION_BANK_CD_DSIDE_ACCESS = 0x95,
119 SCORPION_BANK_AB_ISIDE_HIT = 0x96,
120 SCORPION_BANK_AB_ISIDE_ACCESS = 0x97,
121 SCORPION_BANK_CD_ISIDE_HIT = 0x98,
122 SCORPION_BANK_CD_ISIDE_ACCESS = 0x99,
123 SCORPION_ISIDE_RD_WAIT = 0x9a,
124 SCORPION_DSIDE_RD_WAIT = 0x9b,
125 SCORPION_BANK_BYPASS_WRITE = 0x9c,
126 SCORPION_BANK_AB_NON_CASTOUT = 0x9d,
127 SCORPION_BANK_AB_L2_CASTOUT = 0x9e,
128 SCORPION_BANK_CD_NON_CASTOUT = 0x9f,
129 SCORPION_BANK_CD_L2_CASTOUT = 0xa0,
130#endif
131 MSM_MAX_EVT
132};
133
134struct scorp_evt {
135 u32 evt_type;
136 u32 val;
137 u8 grp;
138 u32 evt_type_act;
139};
140
141static const struct scorp_evt sc_evt[] = {
142 {SCORPION_ICACHE_EXPL_INV, 0x80000500, 0, 0x4d},
143 {SCORPION_ICACHE_MISS, 0x80050000, 0, 0x4e},
144 {SCORPION_ICACHE_ACCESS, 0x85000000, 0, 0x4f},
145 {SCORPION_ICACHE_CACHEREQ_L2, 0x86000000, 0, 0x4f},
146 {SCORPION_ICACHE_NOCACHE_L2, 0x87000000, 0, 0x4f},
147 {SCORPION_HIQUP_NOPED, 0x80080000, 0, 0x4e},
148 {SCORPION_DATA_ABORT, 0x8000000a, 0, 0x4c},
149 {SCORPION_IRQ, 0x80000a00, 0, 0x4d},
150 {SCORPION_FIQ, 0x800a0000, 0, 0x4e},
151 {SCORPION_ALL_EXCPT, 0x8a000000, 0, 0x4f},
152 {SCORPION_UNDEF, 0x8000000b, 0, 0x4c},
153 {SCORPION_SVC, 0x80000b00, 0, 0x4d},
154 {SCORPION_SMC, 0x800b0000, 0, 0x4e},
155 {SCORPION_PREFETCH_ABORT, 0x8b000000, 0, 0x4f},
156 {SCORPION_INDEX_CHECK, 0x8000000c, 0, 0x4c},
157 {SCORPION_NULL_CHECK, 0x80000c00, 0, 0x4d},
158 {SCORPION_EXPL_ICIALLU, 0x8000000d, 0, 0x4c},
159 {SCORPION_IMPL_ICIALLU, 0x80000d00, 0, 0x4d},
160 {SCORPION_NONICIALLU_BTAC_INV, 0x800d0000, 0, 0x4e},
161 {SCORPION_ICIMVAU_IMPL_ICIALLU, 0x8d000000, 0, 0x4f},
162
163 {SCORPION_SPIPE_ONLY_CYCLES, 0x80000600, 1, 0x51},
164 {SCORPION_XPIPE_ONLY_CYCLES, 0x80060000, 1, 0x52},
165 {SCORPION_DUAL_CYCLES, 0x86000000, 1, 0x53},
166 {SCORPION_DISPATCH_ANY_CYCLES, 0x89000000, 1, 0x53},
167 {SCORPION_FIFO_FULLBLK_CMT, 0x8000000d, 1, 0x50},
168 {SCORPION_FAIL_COND_INST, 0x800d0000, 1, 0x52},
169 {SCORPION_PASS_COND_INST, 0x8d000000, 1, 0x53},
170 {SCORPION_ALLOW_VU_CLK, 0x8000000e, 1, 0x50},
171 {SCORPION_VU_IDLE, 0x80000e00, 1, 0x51},
172 {SCORPION_ALLOW_L2_CLK, 0x800e0000, 1, 0x52},
173 {SCORPION_L2_IDLE, 0x8e000000, 1, 0x53},
174
175 {SCORPION_DTLB_IMPL_INV_SCTLR_DACR, 0x80000001, 2, 0x54},
176 {SCORPION_DTLB_EXPL_INV, 0x80000100, 2, 0x55},
177 {SCORPION_DTLB_MISS, 0x80010000, 2, 0x56},
178 {SCORPION_DTLB_ACCESS, 0x81000000, 2, 0x57},
179 {SCORPION_ITLB_MISS, 0x80000200, 2, 0x55},
180 {SCORPION_ITLB_IMPL_INV, 0x80020000, 2, 0x56},
181 {SCORPION_ITLB_EXPL_INV, 0x82000000, 2, 0x57},
182 {SCORPION_UTLB_D_MISS, 0x80000003, 2, 0x54},
183 {SCORPION_UTLB_D_ACCESS, 0x80000300, 2, 0x55},
184 {SCORPION_UTLB_I_MISS, 0x80030000, 2, 0x56},
185 {SCORPION_UTLB_I_ACCESS, 0x83000000, 2, 0x57},
186 {SCORPION_UTLB_INV_ASID, 0x80000400, 2, 0x55},
187 {SCORPION_UTLB_INV_MVA, 0x80040000, 2, 0x56},
188 {SCORPION_UTLB_INV_ALL, 0x84000000, 2, 0x57},
189 {SCORPION_S2_HOLD_RDQ_UNAVAIL, 0x80000800, 2, 0x55},
190 {SCORPION_S2_HOLD, 0x88000000, 2, 0x57},
191 {SCORPION_S2_HOLD_DEV_OP, 0x80000900, 2, 0x55},
192 {SCORPION_S2_HOLD_ORDER, 0x80090000, 2, 0x56},
193 {SCORPION_S2_HOLD_BARRIER, 0x89000000, 2, 0x57},
194
195 {SCORPION_VIU_DUAL_CYCLE, 0x80000001, 4, 0x5c},
196 {SCORPION_VIU_SINGLE_CYCLE, 0x80000100, 4, 0x5d},
197 {SCORPION_VX_PIPE_WAR_STALL_CYCLES, 0x80000005, 4, 0x5c},
198 {SCORPION_VX_PIPE_WAW_STALL_CYCLES, 0x80000500, 4, 0x5d},
199 {SCORPION_VX_PIPE_RAW_STALL_CYCLES, 0x80050000, 4, 0x5e},
200 {SCORPION_VX_PIPE_LOAD_USE_STALL, 0x80000007, 4, 0x5c},
201 {SCORPION_VS_PIPE_WAR_STALL_CYCLES, 0x80000008, 4, 0x5c},
202 {SCORPION_VS_PIPE_WAW_STALL_CYCLES, 0x80000800, 4, 0x5d},
203 {SCORPION_VS_PIPE_RAW_STALL_CYCLES, 0x80080000, 4, 0x5e},
204 {SCORPION_EXCEPTIONS_INV_OPERATION, 0x8000000b, 4, 0x5c},
205 {SCORPION_EXCEPTIONS_DIV_BY_ZERO, 0x80000b00, 4, 0x5d},
206 {SCORPION_COND_INST_FAIL_VX_PIPE, 0x800b0000, 4, 0x5e},
207 {SCORPION_COND_INST_FAIL_VS_PIPE, 0x8b000000, 4, 0x5f},
208 {SCORPION_EXCEPTIONS_OVERFLOW, 0x8000000c, 4, 0x5c},
209 {SCORPION_EXCEPTIONS_UNDERFLOW, 0x80000c00, 4, 0x5d},
210 {SCORPION_EXCEPTIONS_DENORM, 0x8c000000, 4, 0x5f},
211
212 {SCORPION_BANK_AB_HIT, 0x80000001, 3, 0x58},
213 {SCORPION_BANK_AB_ACCESS, 0x80000100, 3, 0x59},
214 {SCORPION_BANK_CD_HIT, 0x80010000, 3, 0x5a},
215 {SCORPION_BANK_CD_ACCESS, 0x81000000, 3, 0x5b},
216 {SCORPION_BANK_AB_DSIDE_HIT, 0x80000002, 3, 0x58},
217 {SCORPION_BANK_AB_DSIDE_ACCESS, 0x80000200, 3, 0x59},
218 {SCORPION_BANK_CD_DSIDE_HIT, 0x80020000, 3, 0x5a},
219 {SCORPION_BANK_CD_DSIDE_ACCESS, 0x82000000, 3, 0x5b},
220 {SCORPION_BANK_AB_ISIDE_HIT, 0x80000003, 3, 0x58},
221 {SCORPION_BANK_AB_ISIDE_ACCESS, 0x80000300, 3, 0x59},
222 {SCORPION_BANK_CD_ISIDE_HIT, 0x80030000, 3, 0x5a},
223 {SCORPION_BANK_CD_ISIDE_ACCESS, 0x83000000, 3, 0x5b},
224 {SCORPION_ISIDE_RD_WAIT, 0x80000009, 3, 0x58},
225 {SCORPION_DSIDE_RD_WAIT, 0x80090000, 3, 0x5a},
226 {SCORPION_BANK_BYPASS_WRITE, 0x8000000a, 3, 0x58},
227 {SCORPION_BANK_AB_NON_CASTOUT, 0x8000000c, 3, 0x58},
228 {SCORPION_BANK_AB_L2_CASTOUT, 0x80000c00, 3, 0x59},
229 {SCORPION_BANK_CD_NON_CASTOUT, 0x800c0000, 3, 0x5a},
230 {SCORPION_BANK_CD_L2_CASTOUT, 0x8c000000, 3, 0x5b},
231};
232
233static inline void scorpion_pmnc_write(u32 val)
234{
235 val &= PMNC_MASK;
236 asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val));
237}
238
239static inline u32 scorpion_pmnc_read(void)
240{
241 u32 val;
242 asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
243 return val;
244}
245
246static inline u32 scorpion_ccnt_read(void)
247{
248 u32 val;
249 asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));
250 return val;
251}
252
253static inline u32 scorpion_cntn_read(void)
254{
255 u32 val;
256 asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val));
257 return val;
258}
259
260static inline u32 scorpion_pmnc_enable_counter(unsigned int cnt)
261{
262 u32 val;
263
264 if (cnt >= CNTMAX) {
265 pr_err("gator: CPU%u enabling wrong PMNC counter %d\n", smp_processor_id(), cnt);
266 return -1;
267 }
268
269 if (cnt == CCNT)
270 val = CCNT_REG;
271 else
272 val = (1 << (cnt - CNT0));
273
274 asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
275
276 return cnt;
277}
278
279static inline u32 scorpion_pmnc_disable_counter(unsigned int cnt)
280{
281 u32 val;
282
283 if (cnt >= CNTMAX) {
284 pr_err("gator: CPU%u disabling wrong PMNC counter %d\n", smp_processor_id(), cnt);
285 return -1;
286 }
287
288 if (cnt == CCNT)
289 val = CCNT_REG;
290 else
291 val = (1 << (cnt - CNT0));
292
293 asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
294
295 return cnt;
296}
297
298static inline int scorpion_pmnc_select_counter(unsigned int cnt)
299{
300 u32 val;
301
302 if ((cnt == CCNT) || (cnt >= CNTMAX)) {
303 pr_err("gator: CPU%u selecting wrong PMNC counter %d\n", smp_processor_id(), cnt);
304 return -1;
305 }
306
307 val = (cnt - CNT0);
308 asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
309
310 return cnt;
311}
312
313static u32 scorpion_read_lpm0(void)
314{
315 u32 val;
316 asm volatile("mrc p15, 0, %0, c15, c0, 0" : "=r" (val));
317 return val;
318}
319
320static void scorpion_write_lpm0(u32 val)
321{
322 asm volatile("mcr p15, 0, %0, c15, c0, 0" : : "r" (val));
323}
324
325static u32 scorpion_read_lpm1(void)
326{
327 u32 val;
328 asm volatile("mrc p15, 1, %0, c15, c0, 0" : "=r" (val));
329 return val;
330}
331
332static void scorpion_write_lpm1(u32 val)
333{
334 asm volatile("mcr p15, 1, %0, c15, c0, 0" : : "r" (val));
335}
336
337static u32 scorpion_read_lpm2(void)
338{
339 u32 val;
340 asm volatile("mrc p15, 2, %0, c15, c0, 0" : "=r" (val));
341 return val;
342}
343
344static void scorpion_write_lpm2(u32 val)
345{
346 asm volatile("mcr p15, 2, %0, c15, c0, 0" : : "r" (val));
347}
348
349static u32 scorpion_read_l2lpm(void)
350{
351 u32 val;
352 asm volatile("mrc p15, 3, %0, c15, c2, 0" : "=r" (val));
353 return val;
354}
355
356static void scorpion_write_l2lpm(u32 val)
357{
358 asm volatile("mcr p15, 3, %0, c15, c2, 0" : : "r" (val));
359}
360
361static u32 scorpion_read_vlpm(void)
362{
363 u32 val;
364 asm volatile("mrc p10, 7, %0, c11, c0, 0" : "=r" (val));
365 return val;
366}
367
368static void scorpion_write_vlpm(u32 val)
369{
370 asm volatile("mcr p10, 7, %0, c11, c0, 0" : : "r" (val));
371}
372
373struct scorpion_access_funcs {
374 u32 (*read) (void);
375 void (*write) (u32);
376};
377
378struct scorpion_access_funcs scor_func[] = {
379 {scorpion_read_lpm0, scorpion_write_lpm0},
380 {scorpion_read_lpm1, scorpion_write_lpm1},
381 {scorpion_read_lpm2, scorpion_write_lpm2},
382 {scorpion_read_l2lpm, scorpion_write_l2lpm},
383 {scorpion_read_vlpm, scorpion_write_vlpm},
384};
385
386u32 venum_orig_val;
387u32 fp_orig_val;
388
389static void scorpion_pre_vlpm(void)
390{
391 u32 venum_new_val;
392 u32 fp_new_val;
393
394 /* CPACR Enable CP10 access*/
395 asm volatile("mrc p15, 0, %0, c1, c0, 2" : "=r" (venum_orig_val));
396 venum_new_val = venum_orig_val | 0x00300000;
397 asm volatile("mcr p15, 0, %0, c1, c0, 2" : : "r" (venum_new_val));
398 /* Enable FPEXC */
399 asm volatile("mrc p10, 7, %0, c8, c0, 0" : "=r" (fp_orig_val));
400 fp_new_val = fp_orig_val | 0x40000000;
401 asm volatile("mcr p10, 7, %0, c8, c0, 0" : : "r" (fp_new_val));
402}
403
404static void scorpion_post_vlpm(void)
405{
406 /* Restore FPEXC*/
407 asm volatile("mcr p10, 7, %0, c8, c0, 0" : : "r" (fp_orig_val));
408 /* Restore CPACR*/
409 asm volatile("mcr p15, 0, %0, c1, c0, 2" : : "r" (venum_orig_val));
410}
411
412#define COLMN0MASK 0x000000ff
413#define COLMN1MASK 0x0000ff00
414#define COLMN2MASK 0x00ff0000
415static u32 scorpion_get_columnmask(u32 setval)
416{
417 if (setval & COLMN0MASK)
418 return 0xffffff00;
419 else if (setval & COLMN1MASK)
420 return 0xffff00ff;
421 else if (setval & COLMN2MASK)
422 return 0xff00ffff;
423 else
424 return 0x80ffffff;
425}
426
427static void scorpion_evt_setup(u32 gr, u32 setval)
428{
429 u32 val;
430 if (gr == 4)
431 scorpion_pre_vlpm();
432 val = scorpion_get_columnmask(setval) & scor_func[gr].read();
433 val = val | setval;
434 scor_func[gr].write(val);
435 if (gr == 4)
436 scorpion_post_vlpm();
437}
438
439static int get_scorpion_evtinfo(unsigned int evt_type, struct scorp_evt *evtinfo)
440{
441 u32 idx;
442 if ((evt_type < 0x4c) || (evt_type >= MSM_MAX_EVT))
443 return 0;
444 idx = evt_type - 0x4c;
445 if (sc_evt[idx].evt_type == evt_type) {
446 evtinfo->val = sc_evt[idx].val;
447 evtinfo->grp = sc_evt[idx].grp;
448 evtinfo->evt_type_act = sc_evt[idx].evt_type_act;
449 return 1;
450 }
451 return 0;
452}
453
454static inline void scorpion_pmnc_write_evtsel(unsigned int cnt, u32 val)
455{
456 if (scorpion_pmnc_select_counter(cnt) == cnt) {
457 if (val < 0x40) {
458 asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
459 } else {
460 u32 zero = 0;
461 struct scorp_evt evtinfo;
462 // extract evtinfo.grp and evtinfo.tevt_type_act from val
463 if (get_scorpion_evtinfo(val, &evtinfo) == 0) return;
464 asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (evtinfo.evt_type_act));
465 asm volatile("mcr p15, 0, %0, c9, c15, 0" : : "r" (zero));
466 scorpion_evt_setup(evtinfo.grp, val);
467 }
468 }
469}
470
471static void scorpion_pmnc_reset_counter(unsigned int cnt)
472{
473 u32 val = 0;
474
475 if (cnt == CCNT) {
476 scorpion_pmnc_disable_counter(cnt);
477
478 asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (val));
479
480 if (pmnc_enabled[cnt] != 0)
481 scorpion_pmnc_enable_counter(cnt);
482
483 } else if (cnt >= CNTMAX) {
484 pr_err("gator: CPU%u resetting wrong PMNC counter %d\n", smp_processor_id(), cnt);
485 } else {
486 scorpion_pmnc_disable_counter(cnt);
487
488 if (scorpion_pmnc_select_counter(cnt) == cnt)
489 asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (val));
490
491 if (pmnc_enabled[cnt] != 0)
492 scorpion_pmnc_enable_counter(cnt);
493 }
494}
495
496static int gator_events_scorpion_create_files(struct super_block *sb, struct dentry *root)
497{
498 struct dentry *dir;
499 int i;
500
501 for (i = 0; i < pmnc_count; i++) {
502 char buf[40];
503 if (i == 0) {
504 snprintf(buf, sizeof buf, "%s_ccnt", pmnc_name);
505 } else {
506 snprintf(buf, sizeof buf, "%s_cnt%d", pmnc_name, i-1);
507 }
508 dir = gatorfs_mkdir(sb, root, buf);
509 if (!dir) {
510 return -1;
511 }
512 gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
513 if (i > 0) {
514 gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
515 }
516 gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
517 }
518
519 return 0;
520}
521
522static void gator_events_scorpion_online(void)
523{
524 unsigned int cnt;
525
526 if (scorpion_pmnc_read() & PMNC_E) {
527 scorpion_pmnc_write(scorpion_pmnc_read() & ~PMNC_E);
528 }
529
530 /* Initialize & Reset PMNC: C bit and P bit */
531 scorpion_pmnc_write(PMNC_P | PMNC_C);
532
533 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
534 unsigned long event;
535
536 per_cpu(perfPrev, smp_processor_id())[cnt] = 0;
537
538 if (!pmnc_enabled[cnt])
539 continue;
540
541 // disable counter
542 scorpion_pmnc_disable_counter(cnt);
543
544 event = pmnc_event[cnt] & 255;
545
546 // Set event (if destined for PMNx counters), We don't need to set the event if it's a cycle count
547 if (cnt != CCNT)
548 scorpion_pmnc_write_evtsel(cnt, event);
549
550 // reset counter
551 scorpion_pmnc_reset_counter(cnt);
552
553 // Enable counter, do not enable interrupt for this counter
554 scorpion_pmnc_enable_counter(cnt);
555 }
556
557 // enable
558 scorpion_pmnc_write(scorpion_pmnc_read() | PMNC_E);
559}
560
561static void gator_events_scorpion_offline(void)
562{
563 scorpion_pmnc_write(scorpion_pmnc_read() & ~PMNC_E);
564
565 // investigate: need to do the clearpmu() here on each counter?
566}
567
568static void gator_events_scorpion_stop(void)
569{
570 unsigned int cnt;
571
572 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
573 pmnc_enabled[cnt] = 0;
574 pmnc_event[cnt] = 0;
575 }
576}
577
578static int gator_events_scorpion_read(int **buffer)
579{
580 int cnt, len = 0;
581 int cpu = smp_processor_id();
582
583 if (!pmnc_count)
584 return 0;
585
586 for (cnt = 0; cnt < pmnc_count; cnt++) {
587 if (pmnc_enabled[cnt]) {
588 int value;
589 if (cnt == CCNT) {
590 value = scorpion_ccnt_read();
591 } else if (scorpion_pmnc_select_counter(cnt) == cnt) {
592 value = scorpion_cntn_read();
593 } else {
594 value = 0;
595 }
596 scorpion_pmnc_reset_counter(cnt);
597 if (value != per_cpu(perfPrev, cpu)[cnt]) {
598 per_cpu(perfPrev, cpu)[cnt] = value;
599 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
600 per_cpu(perfCnt, cpu)[len++] = value;
601 }
602 }
603 }
604
605 // update or discard
606 if (buffer)
607 *buffer = per_cpu(perfCnt, cpu);
608
609 return len;
610}
611
612static struct gator_interface gator_events_scorpion_interface = {
613 .create_files = gator_events_scorpion_create_files,
614 .stop = gator_events_scorpion_stop,
615 .online = gator_events_scorpion_online,
616 .offline = gator_events_scorpion_offline,
617 .read = gator_events_scorpion_read,
618};
619
620
621static void scorpion_clear_pmuregs(void)
622{
623 scorpion_write_lpm0(0);
624 scorpion_write_lpm1(0);
625 scorpion_write_lpm2(0);
626 scorpion_write_l2lpm(0);
627 scorpion_pre_vlpm();
628 scorpion_write_vlpm(0);
629 scorpion_post_vlpm();
630}
631
632int gator_events_scorpion_init(void)
633{
634 unsigned int cnt;
635
636 switch (gator_cpuid()) {
637 case SCORPION:
638 pmnc_name = "Scorpion";
639 pmnc_count = 4;
640 break;
641 case SCORPIONMP:
642 pmnc_name = "ScorpionMP";
643 pmnc_count = 4;
644 break;
645 default:
646 return -1;
647 }
648
649 pmnc_count++; // CNT[n] + CCNT
650
651 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
652 pmnc_enabled[cnt] = 0;
653 pmnc_event[cnt] = 0;
654 pmnc_key[cnt] = gator_events_get_key();
655 }
656
657 scorpion_clear_pmuregs();
658
659 return gator_events_install(&gator_events_scorpion_interface);
660}
661gator_events_init(gator_events_scorpion_init);
diff --git a/gator_fs.c b/gator_fs.c
index f7cbff2..8277c3a 100644
--- a/gator_fs.c
+++ b/gator_fs.c
@@ -20,8 +20,6 @@
20#define TMPBUFSIZE 50 20#define TMPBUFSIZE 50
21DEFINE_SPINLOCK(gatorfs_lock); 21DEFINE_SPINLOCK(gatorfs_lock);
22 22
23void gator_op_create_files(struct super_block *sb, struct dentry *root);
24
25static struct inode *gatorfs_get_inode(struct super_block *sb, int mode) 23static struct inode *gatorfs_get_inode(struct super_block *sb, int mode)
26{ 24{
27 struct inode *inode = new_inode(sb); 25 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 @@
7 * 7 *
8 */ 8 */
9 9
10static unsigned long gator_protocol_version = 4; 10static unsigned long gator_protocol_version = 5;
11 11
12#include "gator.h"
13#include <linux/slab.h> 12#include <linux/slab.h>
14#include <linux/cpu.h> 13#include <linux/cpu.h>
15#include <linux/sched.h> 14#include <linux/sched.h>
@@ -20,23 +19,26 @@ static unsigned long gator_protocol_version = 4;
20#include <linux/pagemap.h> 19#include <linux/pagemap.h>
21#include <asm/uaccess.h> 20#include <asm/uaccess.h>
22 21
22#include "gator.h"
23#include "gator_events.h"
24
23#ifndef CONFIG_GENERIC_TRACER 25#ifndef CONFIG_GENERIC_TRACER
24#ifndef CONFIG_TRACING 26#ifndef CONFIG_TRACING
25#warning gator requires the kernel to have CONFIG_GENERIC_TRACER or CONFIG_TRACING defined 27#error gator requires the kernel to have CONFIG_GENERIC_TRACER or CONFIG_TRACING defined
26#endif 28#endif
27#endif 29#endif
28 30
29#ifndef CONFIG_PROFILING 31#ifndef CONFIG_PROFILING
30#warning gator requires the kernel to have CONFIG_PROFILING defined 32#error gator requires the kernel to have CONFIG_PROFILING defined
31#endif 33#endif
32 34
33#ifndef CONFIG_HIGH_RES_TIMERS 35#ifndef CONFIG_HIGH_RES_TIMERS
34#warning gator requires the kernel to have CONFIG_HIGH_RES_TIMERS defined 36#error gator requires the kernel to have CONFIG_HIGH_RES_TIMERS defined
35#endif 37#endif
36 38
37#ifdef CONFIG_SMP 39#ifdef CONFIG_SMP
38#ifndef CONFIG_LOCAL_TIMERS 40#ifndef CONFIG_LOCAL_TIMERS
39#warning gator requires the kernel to have CONFIG_LOCAL_TIMERS defined on SMP systems 41#error gator requires the kernel to have CONFIG_LOCAL_TIMERS defined on SMP systems
40#endif 42#endif
41#endif 43#endif
42 44
@@ -80,7 +82,7 @@ static unsigned long gator_backtrace_depth;
80static unsigned long gator_started; 82static unsigned long gator_started;
81static unsigned long gator_buffer_opened; 83static unsigned long gator_buffer_opened;
82static unsigned long gator_timer_count; 84static unsigned long gator_timer_count;
83static unsigned long gator_sync_freq; 85static unsigned long gator_streaming;
84static int gator_master_tick; 86static int gator_master_tick;
85static DEFINE_MUTEX(start_mutex); 87static DEFINE_MUTEX(start_mutex);
86static DEFINE_MUTEX(gator_buffer_mutex); 88static DEFINE_MUTEX(gator_buffer_mutex);
@@ -104,6 +106,7 @@ static DEFINE_PER_CPU(int, gator_first_time);
104 ******************************************************************************/ 106 ******************************************************************************/
105static void gator_buffer_write_packed_int(int cpu, unsigned int x); 107static void gator_buffer_write_packed_int(int cpu, unsigned int x);
106static void gator_buffer_write_string(int cpu, char *x); 108static void gator_buffer_write_string(int cpu, char *x);
109static int gator_write_packed_int(char *buffer, unsigned int x);
107static void gator_add_trace(int cpu, unsigned int address); 110static void gator_add_trace(int cpu, unsigned int address);
108static uint64_t gator_get_time(void); 111static uint64_t gator_get_time(void);
109 112
@@ -114,7 +117,6 @@ static uint64_t gator_get_time(void);
114#include "gator_trace_sched.c" 117#include "gator_trace_sched.c"
115#include "gator_backtrace.c" 118#include "gator_backtrace.c"
116#include "gator_annotate.c" 119#include "gator_annotate.c"
117#include "gator_events.c"
118#include "gator_fs.c" 120#include "gator_fs.c"
119 121
120/****************************************************************************** 122/******************************************************************************
@@ -204,6 +206,36 @@ static void gator_buffer_write_packed_int(int cpu, unsigned int x)
204 } 206 }
205} 207}
206 208
209static int gator_write_packed_int(char *buffer, unsigned int x)
210{
211 if ((x & 0xffffff80) == 0) {
212 buffer[0] = x & 0x7f;
213 return 1;
214 } else if ((x & 0xffffc000) == 0) {
215 buffer[0] = x | 0x80;
216 buffer[1] = (x>>7) & 0x7f;
217 return 2;
218 } else if ((x & 0xffe00000) == 0) {
219 buffer[0] = x | 0x80;
220 buffer[1] = (x>>7) | 0x80;
221 buffer[2] = (x>>14) & 0x7f;
222 return 3;
223 } else if ((x & 0xf0000000) == 0) {
224 buffer[0] = x | 0x80;
225 buffer[1] = (x>>7) | 0x80;
226 buffer[2] = (x>>14) | 0x80;
227 buffer[3] = (x>>21) & 0x7f;
228 return 4;
229 } else {
230 buffer[0] = x | 0x80;
231 buffer[1] = (x>>7) | 0x80;
232 buffer[2] = (x>>14) | 0x80;
233 buffer[3] = (x>>21) | 0x80;
234 buffer[4] = (x>>28) & 0x0f;
235 return 5;
236 }
237}
238
207static void gator_buffer_write_bytes(int cpu, char *x, int len) 239static void gator_buffer_write_bytes(int cpu, char *x, int len)
208{ 240{
209 uint32_t write = per_cpu(use_buffer_write, cpu); 241 uint32_t write = per_cpu(use_buffer_write, cpu);
@@ -244,7 +276,7 @@ static void gator_buffer_commit(int cpu)
244 276
245static void gator_buffer_check(int cpu, int tick) 277static void gator_buffer_check(int cpu, int tick)
246{ 278{
247 if (gator_sync_freq && !(tick % gator_sync_freq)) { 279 if (!(tick % gator_timer_count)) {
248 int c, sync; 280 int c, sync;
249 spin_lock(&gator_commit_lock); 281 spin_lock(&gator_commit_lock);
250 // synchronize, if all online cpus have the same tick waypoint 282 // synchronize, if all online cpus have the same tick waypoint
@@ -258,7 +290,6 @@ static void gator_buffer_check(int cpu, int tick)
258 if (sync) { 290 if (sync) {
259 gator_buffer_write_packed_int(cpu, PROTOCOL_CPU_SYNC); 291 gator_buffer_write_packed_int(cpu, PROTOCOL_CPU_SYNC);
260 } 292 }
261 // commit the buffer
262 gator_buffer_commit(cpu); 293 gator_buffer_commit(cpu);
263 spin_unlock(&gator_commit_lock); 294 spin_unlock(&gator_commit_lock);
264 } else { 295 } else {
@@ -336,46 +367,27 @@ static void gator_write_packet(int cpu, int type, int len, int *buffer)
336 } 367 }
337} 368}
338 369
339static void gator_write_annotate(int cpu, int len, int *buffer)
340{
341 int pos = 0;
342
343 while (pos < len) {
344 unsigned int tid = buffer[pos++];
345 unsigned int bytes = buffer[pos++];
346 unsigned int words = (bytes + 3) / 4;
347 char *ptr = (char *)&buffer[pos];
348 pos += words;
349
350 gator_buffer_write_packed_int(cpu, PROTOCOL_ANNOTATE);
351 gator_buffer_write_packed_int(cpu, tid);
352 gator_buffer_write_packed_int(cpu, bytes);
353 gator_buffer_write_bytes(cpu, ptr, bytes);
354 }
355}
356
357/****************************************************************************** 370/******************************************************************************
358 * Interrupt Processing 371 * Interrupt Processing
359 ******************************************************************************/ 372 ******************************************************************************/
360static gator_interface *gi = NULL; 373static LIST_HEAD(gator_events);
361 374
362static void gator_timer_interrupt(void) 375static void gator_timer_interrupt(void)
363{ 376{
364 struct pt_regs * const regs = get_irq_regs(); 377 struct pt_regs * const regs = get_irq_regs();
365 int cpu = raw_smp_processor_id(); 378 int cpu = smp_processor_id();
366 int *buffer, len, tick; 379 int *buffer, len, tick;
367 gator_interface *i; 380 struct gator_interface *gi;
368 381
369 // check full backtrace has enough space, otherwise may 382 // check full backtrace has enough space, otherwise may
370 // have breaks between samples in the same callstack 383 // have breaks between samples in the same callstack
371 if (per_cpu(gator_first_time, cpu)) { 384 if (per_cpu(gator_first_time, cpu)) {
372 per_cpu(gator_first_time, cpu) = 0; 385 per_cpu(gator_first_time, cpu) = 0;
373 386
374 for (i = gi; i != NULL; i = i->next) { 387 list_for_each_entry(gi, &gator_events, list)
375 if (i->read) { 388 if (gi->read)
376 i->read(NULL); 389 gi->read(NULL);
377 } 390
378 }
379 return; 391 return;
380 } 392 }
381 393
@@ -388,18 +400,12 @@ static void gator_timer_interrupt(void)
388 gator_write_packet(cpu, PROTOCOL_SCHEDULER_TRACE, len, buffer); 400 gator_write_packet(cpu, PROTOCOL_SCHEDULER_TRACE, len, buffer);
389 } 401 }
390 402
391 // Output annotate
392 len = gator_annotate_read(&buffer);
393 if (len > 0)
394 gator_write_annotate(cpu, len, buffer);
395
396 // Output counters 403 // Output counters
397 for (i = gi; i != NULL; i = i->next) { 404 list_for_each_entry(gi, &gator_events, list) {
398 if (i->read) { 405 if (gi->read) {
399 len = i->read(&buffer); 406 len = gi->read(&buffer);
400 if (len > 0) { 407 if (len > 0)
401 gator_write_packet(cpu, PROTOCOL_COUNTERS, len, buffer); 408 gator_write_packet(cpu, PROTOCOL_COUNTERS, len, buffer);
402 }
403 } 409 }
404 } 410 }
405 411
@@ -444,18 +450,16 @@ static void __gator_timer_offline(void *unused)
444{ 450{
445 int cpu = smp_processor_id(); 451 int cpu = smp_processor_id();
446 if (per_cpu(hrtimer_is_active, cpu)) { 452 if (per_cpu(hrtimer_is_active, cpu)) {
447 gator_interface *i; 453 struct gator_interface *gi;
448 struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu); 454 struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu);
449 hrtimer_cancel(hrtimer); 455 hrtimer_cancel(hrtimer);
450 per_cpu(hrtimer_is_active, cpu) = 0; 456 per_cpu(hrtimer_is_active, cpu) = 0;
451 gator_buffer_commit(cpu); 457 gator_buffer_commit(cpu);
452 458
453 // offline any events 459 // offline any events
454 for (i = gi; i != NULL; i = i->next) { 460 list_for_each_entry(gi, &gator_events, list)
455 if (i->offline) { 461 if (gi->offline)
456 i->offline(); 462 gi->offline();
457 }
458 }
459 } 463 }
460} 464}
461 465
@@ -476,7 +480,7 @@ static void __gator_timer_online(void *unused)
476{ 480{
477 int cpu = smp_processor_id(); 481 int cpu = smp_processor_id();
478 if (!per_cpu(hrtimer_is_active, cpu)) { 482 if (!per_cpu(hrtimer_is_active, cpu)) {
479 gator_interface *i; 483 struct gator_interface *gi;
480 struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu); 484 struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu);
481 hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 485 hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
482 hrtimer->function = gator_hrtimer_notify; 486 hrtimer->function = gator_hrtimer_notify;
@@ -486,11 +490,9 @@ static void __gator_timer_online(void *unused)
486 per_cpu(hrtimer_is_active, cpu) = 1; 490 per_cpu(hrtimer_is_active, cpu) = 1;
487 491
488 // online any events 492 // online any events
489 for (i = gi; i != NULL; i = i->next) { 493 list_for_each_entry(gi, &gator_events, list)
490 if (i->online) { 494 if (gi->online)
491 i->online(); 495 gi->online();
492 }
493 }
494 } 496 }
495} 497}
496 498
@@ -566,46 +568,23 @@ static void gator_notifier_stop(void)
566/****************************************************************************** 568/******************************************************************************
567 * Main 569 * Main
568 ******************************************************************************/ 570 ******************************************************************************/
569int gator_event_install(int (*event_install)(gator_interface *)) 571int gator_events_install(struct gator_interface *interface)
570{ 572{
571 gator_interface *ni = (gator_interface*)kmalloc(sizeof(gator_interface), GFP_KERNEL); 573 list_add_tail(&interface->list, &gator_events);
572 if (ni == NULL) {
573 return -1;
574 }
575
576 ni->create_files = NULL;
577 ni->init = NULL;
578 ni->start = NULL;
579 ni->stop = NULL;
580 ni->online = NULL;
581 ni->offline = NULL;
582 ni->read = NULL;
583 ni->next = NULL;
584
585 // Initialize ni gator interface
586 if (!event_install(ni)) {
587 if (gi == NULL) {
588 // Set gi to point to the first gator interface
589 gi = ni;
590 } else {
591 // Link the gator interfaces
592 gator_interface *i = gi;
593 while (i->next) {
594 i = i->next;
595 }
596 i->next = ni;
597 }
598 } else {
599 kfree(ni);
600 }
601 574
602 return 0; 575 return 0;
603} 576}
604 577
578int gator_events_get_key(void)
579{
580 static int key;
581
582 return key++;
583}
584
605static int gator_init(void) 585static int gator_init(void)
606{ 586{
607 gator_interface *i; 587 int i;
608 int key = 0;
609 588
610 if (gator_timer_init()) 589 if (gator_timer_init())
611 return -1; 590 return -1;
@@ -614,32 +593,33 @@ static int gator_init(void)
614 if (gator_annotate_init()) 593 if (gator_annotate_init())
615 return -1; 594 return -1;
616 595
617 // set up gator interface linked list structure 596 // events sources (gator_events.h, generated by gator_events.sh)
618 if (gator_events_install()) 597 for (i = 0; i < ARRAY_SIZE(gator_events_list); i++)
619 return -1; 598 if (gator_events_list[i])
620 599 gator_events_list[i]();
621 // initialize all events
622 for (i = gi; i != NULL; i = i->next) {
623 if (i->init) {
624 if (i->init(&key)) {
625 return -1;
626 }
627 }
628 }
629 600
630 return 0; 601 return 0;
631} 602}
632 603
633static int gator_start(void) 604static int gator_start(void)
634{ 605{
635 gator_interface *i, *f; 606 struct gator_interface *gi;
636 607
637 // start all events 608 // start all events
638 for (i = gi; i != NULL; i = i->next) { 609 list_for_each_entry(gi, &gator_events, list) {
639 if (i->start) { 610 if (gi->start && gi->start() != 0) {
640 if (i->start()) { 611 struct list_head *ptr = gi->list.prev;
641 goto events_failure; 612
613 while (ptr != &gator_events) {
614 gi = list_entry(ptr, struct gator_interface,
615 list);
616
617 if (gi->stop)
618 gi->stop();
619
620 ptr = ptr->prev;
642 } 621 }
622 goto events_failure;
643 } 623 }
644 } 624 }
645 625
@@ -662,23 +642,18 @@ sched_failure:
662 gator_annotate_stop(); 642 gator_annotate_stop();
663annotate_failure: 643annotate_failure:
664events_failure: 644events_failure:
665 for (f = gi; f != i; f = f->next) {
666 f->stop();
667 }
668 645
669 return -1; 646 return -1;
670} 647}
671 648
672static void gator_stop(void) 649static void gator_stop(void)
673{ 650{
674 gator_interface *i; 651 struct gator_interface *gi;
675 652
676 // stop all events 653 // stop all events
677 for (i = gi; i != NULL; i = i->next) { 654 list_for_each_entry(gi, &gator_events, list)
678 if (i->stop) { 655 if (gi->stop)
679 i->stop(); 656 gi->stop();
680 }
681 }
682 657
683 gator_annotate_stop(); 658 gator_annotate_stop();
684 gator_trace_sched_stop(); 659 gator_trace_sched_stop();
@@ -690,13 +665,7 @@ static void gator_stop(void)
690 665
691static void gator_exit(void) 666static void gator_exit(void)
692{ 667{
693 gator_interface *i = gi; 668 gator_annotate_exit();
694
695 while (i) {
696 gator_interface *p = i;
697 i = i->next;
698 kfree(p);
699 }
700} 669}
701 670
702/****************************************************************************** 671/******************************************************************************
@@ -894,6 +863,7 @@ static ssize_t event_buffer_read(struct file *file, char __user *buf,
894 int retval = -EINVAL; 863 int retval = -EINVAL;
895 int commit, length1, length2, read; 864 int commit, length1, length2, read;
896 char *buffer1, *buffer2; 865 char *buffer1, *buffer2;
866 char annotate_header[6];
897 int cpu; 867 int cpu;
898 868
899 /* do not handle partial reads */ 869 /* do not handle partial reads */
@@ -902,34 +872,43 @@ static ssize_t event_buffer_read(struct file *file, char __user *buf,
902 872
903 // sleep until the condition is true or a signal is received 873 // sleep until the condition is true or a signal is received
904 // the condition is checked each time gator_buffer_wait is woken up 874 // the condition is checked each time gator_buffer_wait is woken up
905 wait_event_interruptible(gator_buffer_wait, buffer_commit_ready() || !gator_started); 875 wait_event_interruptible(gator_buffer_wait, buffer_commit_ready() || gator_annotate_ready() || !gator_started);
906 876
907 if (signal_pending(current)) 877 if (signal_pending(current))
908 return -EINTR; 878 return -EINTR;
909 879
910 if (!buffer_commit_ready()) 880 retval = -EFAULT;
911 return 0;
912
913 buffer_commit_read(&cpu, &read, &commit);
914 881
915 mutex_lock(&gator_buffer_mutex); 882 mutex_lock(&gator_buffer_mutex);
916 883
917 retval = -EFAULT; 884 if (buffer_commit_ready()) {
885 buffer_commit_read(&cpu, &read, &commit);
918 886
919 /* May happen if the buffer is freed during pending reads. */ 887 /* May happen if the buffer is freed during pending reads. */
920 if (!per_cpu(use_buffer, cpu)) { 888 if (!per_cpu(use_buffer, cpu)) {
921 retval = -EFAULT; 889 retval = -EFAULT;
922 goto out; 890 goto out;
923 } 891 }
924 892
925 /* determine the size of two halves */ 893 /* determine the size of two halves */
926 length1 = commit - read; 894 length1 = commit - read;
927 length2 = 0; 895 length2 = 0;
928 buffer1 = &(per_cpu(use_buffer, cpu)[read]); 896 buffer1 = &(per_cpu(use_buffer, cpu)[read]);
929 buffer2 = &(per_cpu(use_buffer, cpu)[0]); 897 buffer2 = &(per_cpu(use_buffer, cpu)[0]);
930 if (length1 < 0) { 898 if (length1 < 0) {
931 length1 = use_buffer_size - read; 899 length1 = use_buffer_size - read;
932 length2 = commit; 900 length2 = commit;
901 }
902 } else if (gator_annotate_ready()) {
903 length2 = gator_annotate_read(&buffer2);
904 if (!length2)
905 goto out;
906 annotate_header[0] = PROTOCOL_ANNOTATE;
907 length1 = gator_write_packed_int(&annotate_header[1], length2) + 1;
908 buffer1 = annotate_header;
909 } else {
910 retval = 0;
911 goto out;
933 } 912 }
934 913
935 /* start, middle or end */ 914 /* start, middle or end */
@@ -952,8 +931,8 @@ static ssize_t event_buffer_read(struct file *file, char __user *buf,
952 wake_up(&gator_buffer_wait); 931 wake_up(&gator_buffer_wait);
953 932
954out: 933out:
955 // do not adjust network stats if in non-streaming buffer mode 934 // only adjust network stats if in streaming mode
956 if (gator_sync_freq) 935 if (gator_streaming)
957 gator_net_traffic += retval; 936 gator_net_traffic += retval;
958 mutex_unlock(&gator_buffer_mutex); 937 mutex_unlock(&gator_buffer_mutex);
959 return retval; 938 return retval;
@@ -1009,7 +988,7 @@ static const struct file_operations cpu_type_fops = {
1009void gator_op_create_files(struct super_block *sb, struct dentry *root) 988void gator_op_create_files(struct super_block *sb, struct dentry *root)
1010{ 989{
1011 struct dentry *dir; 990 struct dentry *dir;
1012 gator_interface *i; 991 struct gator_interface *gi;
1013 int cpu; 992 int cpu;
1014 993
1015 /* reinitialize default values */ 994 /* reinitialize default values */
@@ -1018,7 +997,7 @@ void gator_op_create_files(struct super_block *sb, struct dentry *root)
1018 gator_cpu_cores++; 997 gator_cpu_cores++;
1019 } 998 }
1020 gator_buffer_size = BUFFER_SIZE_DEFAULT; 999 gator_buffer_size = BUFFER_SIZE_DEFAULT;
1021 gator_sync_freq = SYNC_FREQ_DEFAULT; 1000 gator_streaming = 1;
1022 1001
1023 gatorfs_create_file(sb, root, "enable", &enable_fops); 1002 gatorfs_create_file(sb, root, "enable", &enable_fops);
1024 gatorfs_create_file(sb, root, "buffer", &gator_event_buffer_fops); 1003 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)
1027 gatorfs_create_ulong(sb, root, "cpu_cores", &gator_cpu_cores); 1006 gatorfs_create_ulong(sb, root, "cpu_cores", &gator_cpu_cores);
1028 gatorfs_create_ulong(sb, root, "buffer_size", &gator_buffer_size); 1007 gatorfs_create_ulong(sb, root, "buffer_size", &gator_buffer_size);
1029 gatorfs_create_ulong(sb, root, "tick", &gator_timer_count); 1008 gatorfs_create_ulong(sb, root, "tick", &gator_timer_count);
1030 gatorfs_create_ulong(sb, root, "sync_freq", &gator_sync_freq); 1009 gatorfs_create_ulong(sb, root, "streaming", &gator_streaming);
1031 gatorfs_create_ro_ulong(sb, root, "version", &gator_protocol_version); 1010 gatorfs_create_ro_ulong(sb, root, "version", &gator_protocol_version);
1032 1011
1033 // Annotate interface 1012 // Annotate interface
@@ -1035,18 +1014,14 @@ void gator_op_create_files(struct super_block *sb, struct dentry *root)
1035 1014
1036 // Linux Events 1015 // Linux Events
1037 dir = gatorfs_mkdir(sb, root, "events"); 1016 dir = gatorfs_mkdir(sb, root, "events");
1038 for (i = gi; i != NULL; i = i->next) { 1017 list_for_each_entry(gi, &gator_events, list)
1039 if (i->create_files) { 1018 if (gi->create_files)
1040 i->create_files(sb, dir); 1019 gi->create_files(sb, dir);
1041 }
1042 }
1043} 1020}
1044 1021
1045/****************************************************************************** 1022/******************************************************************************
1046 * Module 1023 * Module
1047 ******************************************************************************/ 1024 ******************************************************************************/
1048static int gator_initialized;
1049
1050static int __init gator_module_init(void) 1025static int __init gator_module_init(void)
1051{ 1026{
1052 if (gatorfs_register()) { 1027 if (gatorfs_register()) {
@@ -1058,7 +1033,6 @@ static int __init gator_module_init(void)
1058 return -1; 1033 return -1;
1059 } 1034 }
1060 1035
1061 gator_initialized = 1;
1062#ifdef GATOR_DEBUG 1036#ifdef GATOR_DEBUG
1063 pr_err("gator_module_init"); 1037 pr_err("gator_module_init");
1064#endif 1038#endif
@@ -1072,10 +1046,7 @@ static void __exit gator_module_exit(void)
1072#endif 1046#endif
1073 tracepoint_synchronize_unregister(); 1047 tracepoint_synchronize_unregister();
1074 gatorfs_unregister(); 1048 gatorfs_unregister();
1075 if (gator_initialized) { 1049 gator_exit();
1076 gator_initialized = 0;
1077 gator_exit();
1078 }
1079} 1050}
1080 1051
1081module_init(gator_module_init); 1052module_init(gator_module_init);