satip-axe/kernel/arch/sh/oprofile/op_model_sh_tmu.c

168 lines
3.6 KiB
C

/*
* arch/sh/oprofile/op_model_sh_tmu.c
*
* Copyright (C) 2010 STMicroelectronics
* Author : Marc Titinger <marc.titinger-amesys@st.com>
*
* oprofile sh model using the "generic timer" API
* from Stuart Menefy for interrupt trigger.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/smp.h>
#include <linux/oprofile.h>
#include <linux/signal.h>
#include <linux/interrupt.h>
#include <linux/profile.h>
#include <linux/init.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/stm/platform.h>
#include <linux/io.h>
#include <linux/fs.h>
#include <linux/sh_timer.h>
#include "op_impl.h"
#define DEFAULT_SAMPLE_RATE 987 /*Hz*/
static struct sh_timer_callb *timer;
static unsigned long sampling_rate;
/***********************************************************************
* sh_op_tmu_setrate()
*
*
*/
static void sh_op_tmu_setrate(struct op_counter_config *unused)
{
return;
}
static ssize_t sh_op_tmu_read_rate(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
return oprofilefs_ulong_to_user(sampling_rate, buf, count, ppos);
}
static ssize_t sh_op_tmu_write_rate(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long val;
if (oprofilefs_ulong_from_user(&val, buf, count))
return -EFAULT;
if (val > 10000)
sampling_rate = 10000;
if (val < 250)
sampling_rate = 250;
else
sampling_rate = val;
printk(KERN_NOTICE
"please restart the profiler to apply new rate %ld Hz.\n",sampling_rate);
printk(KERN_NOTICE
"You may need to run \"opcontrol --reset\" for data coherence.\n");
return count;
}
static const struct file_operations rate_fops = {
.read = sh_op_tmu_read_rate,
.write = sh_op_tmu_write_rate,
};
static int sh_op_tmu_create_files(struct super_block *sb, struct dentry *dir)
{
return oprofilefs_create_file(sb, dir, "rate", &rate_fops);
}
/***********************************************************************
* sh_op_tmu_irq()
*
*/
static void sh_op_tmu_irq(void *data)
{
struct pt_regs *regs = get_irq_regs();
/* Give the sample to oprofile. */
oprofile_add_sample(regs, 0);
return;
}
/***********************************************************************
* sh_op_tmu_stop()
*
*
*/
static void sh_op_tmu_stop(void *args)
{
if (timer == NULL)
return;
timer->timer_stop(timer->tmu_priv);
sh_timer_unregister(timer->tmu_priv);
timer = NULL;
}
/***********************************************************************
* sh_op_tmu_start()
*
*
*/
static void sh_op_tmu_start(void *args)
{
if (timer == NULL)
timer = sh_timer_register(sh_op_tmu_irq, (void *)0);
if (timer == NULL) {
printk(KERN_ERR "sh_op_tmu_start: no available TMU timer, start failed!\n");
return;
}
printk(KERN_NOTICE "sh_op_tmu_setrate: settings TMU timer at %ld Hz\n",
sampling_rate);
timer->set_rate(timer->tmu_priv, sampling_rate);
timer->timer_start(timer->tmu_priv);
}
int sh_op_tmu_init(void)
{
timer = NULL ;
sampling_rate = DEFAULT_SAMPLE_RATE;
return 0;
}
void sh_op_tmu_exit(void)
{
sh_op_tmu_stop(NULL);
}
static void sh_op_tmu_setup(void *dummy)
{
}
struct op_sh_model op_sh_tmu_ops = {
.cpu_type = "timer", /*for compat with the usermode app*/
.num_counters = 1, /*dir "0"*/
.reg_setup = sh_op_tmu_setrate,
.cpu_setup = sh_op_tmu_setup,
.cpu_start = sh_op_tmu_start,
.cpu_stop = sh_op_tmu_stop,
.init = sh_op_tmu_init,
.exit = sh_op_tmu_exit,
.create_files = sh_op_tmu_create_files,
};