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