2005-04-17 02:20:36 +04:00
/**
* @ file common . c
*
* @ remark Copyright 2004 Oprofile Authors
* @ remark Read the file COPYING
*
* @ author Zwane Mwaikambo
*/
# include <linux/init.h>
# include <linux/oprofile.h>
# include <linux/errno.h>
# include <linux/sysdev.h>
2005-10-28 17:51:15 +04:00
# include <asm/semaphore.h>
2005-04-17 02:20:36 +04:00
# include "op_counter.h"
# include "op_arm_model.h"
2005-10-28 17:54:21 +04:00
static struct op_arm_model_spec * op_arm_model ;
static int op_arm_enabled ;
static struct semaphore op_arm_sem ;
2005-04-17 02:20:36 +04:00
struct op_counter_config counter_config [ OP_MAX_COUNTER ] ;
2005-10-28 17:54:21 +04:00
static int op_arm_create_files ( struct super_block * sb , struct dentry * root )
2005-04-17 02:20:36 +04:00
{
unsigned int i ;
2005-10-28 17:54:21 +04:00
for ( i = 0 ; i < op_arm_model - > num_counters ; i + + ) {
2005-04-17 02:20:36 +04:00
struct dentry * dir ;
char buf [ 2 ] ;
snprintf ( buf , sizeof buf , " %d " , i ) ;
dir = oprofilefs_mkdir ( sb , root , buf ) ;
oprofilefs_create_ulong ( sb , dir , " enabled " , & counter_config [ i ] . enabled ) ;
oprofilefs_create_ulong ( sb , dir , " event " , & counter_config [ i ] . event ) ;
oprofilefs_create_ulong ( sb , dir , " count " , & counter_config [ i ] . count ) ;
oprofilefs_create_ulong ( sb , dir , " unit_mask " , & counter_config [ i ] . unit_mask ) ;
oprofilefs_create_ulong ( sb , dir , " kernel " , & counter_config [ i ] . kernel ) ;
oprofilefs_create_ulong ( sb , dir , " user " , & counter_config [ i ] . user ) ;
}
return 0 ;
}
2005-10-28 17:54:21 +04:00
static int op_arm_setup ( void )
2005-04-17 02:20:36 +04:00
{
int ret ;
spin_lock ( & oprofilefs_lock ) ;
2005-10-28 17:54:21 +04:00
ret = op_arm_model - > setup_ctrs ( ) ;
2005-04-17 02:20:36 +04:00
spin_unlock ( & oprofilefs_lock ) ;
return ret ;
}
2005-10-28 17:54:21 +04:00
static int op_arm_start ( void )
2005-04-17 02:20:36 +04:00
{
int ret = - EBUSY ;
2005-10-28 17:54:21 +04:00
down ( & op_arm_sem ) ;
if ( ! op_arm_enabled ) {
ret = op_arm_model - > start ( ) ;
op_arm_enabled = ! ret ;
2005-04-17 02:20:36 +04:00
}
2005-10-28 17:54:21 +04:00
up ( & op_arm_sem ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
2005-10-28 17:54:21 +04:00
static void op_arm_stop ( void )
2005-04-17 02:20:36 +04:00
{
2005-10-28 17:54:21 +04:00
down ( & op_arm_sem ) ;
if ( op_arm_enabled )
op_arm_model - > stop ( ) ;
op_arm_enabled = 0 ;
up ( & op_arm_sem ) ;
2005-04-17 02:20:36 +04:00
}
2005-10-28 17:51:15 +04:00
# ifdef CONFIG_PM
2005-10-28 17:54:21 +04:00
static int op_arm_suspend ( struct sys_device * dev , pm_message_t state )
2005-10-28 17:51:15 +04:00
{
2005-10-28 17:54:21 +04:00
down ( & op_arm_sem ) ;
if ( op_arm_enabled )
op_arm_model - > stop ( ) ;
up ( & op_arm_sem ) ;
2005-10-28 17:51:15 +04:00
return 0 ;
}
2005-10-28 17:54:21 +04:00
static int op_arm_resume ( struct sys_device * dev )
2005-10-28 17:51:15 +04:00
{
2005-10-28 17:54:21 +04:00
down ( & op_arm_sem ) ;
if ( op_arm_enabled & & op_arm_model - > start ( ) )
op_arm_enabled = 0 ;
up ( & op_arm_sem ) ;
2005-10-28 17:51:15 +04:00
return 0 ;
}
static struct sysdev_class oprofile_sysclass = {
set_kset_name ( " oprofile " ) ,
2005-10-28 17:54:21 +04:00
. resume = op_arm_resume ,
. suspend = op_arm_suspend ,
2005-10-28 17:51:15 +04:00
} ;
static struct sys_device device_oprofile = {
. id = 0 ,
. cls = & oprofile_sysclass ,
} ;
static int __init init_driverfs ( void )
{
int ret ;
if ( ! ( ret = sysdev_class_register ( & oprofile_sysclass ) ) )
ret = sysdev_register ( & device_oprofile ) ;
return ret ;
}
static void exit_driverfs ( void )
{
sysdev_unregister ( & device_oprofile ) ;
sysdev_class_unregister ( & oprofile_sysclass ) ;
}
# else
# define init_driverfs() do { } while (0)
# define exit_driverfs() do { } while (0)
# endif /* CONFIG_PM */
2005-10-28 17:56:04 +04:00
int __init oprofile_arch_init ( struct oprofile_operations * ops )
2005-04-17 02:20:36 +04:00
{
2005-10-28 17:56:04 +04:00
struct op_arm_model_spec * spec = NULL ;
int ret = - ENODEV ;
# ifdef CONFIG_CPU_XSCALE
spec = & op_xscale_spec ;
# endif
if ( spec ) {
init_MUTEX ( & op_arm_sem ) ;
if ( spec - > init ( ) < 0 )
return - ENODEV ;
op_arm_model = spec ;
init_driverfs ( ) ;
ops - > create_files = op_arm_create_files ;
ops - > setup = op_arm_setup ;
ops - > shutdown = op_arm_stop ;
ops - > start = op_arm_start ;
ops - > stop = op_arm_stop ;
ops - > cpu_type = op_arm_model - > name ;
ops - > backtrace = arm_backtrace ;
printk ( KERN_INFO " oprofile: using %s \n " , spec - > name ) ;
}
2005-04-17 02:20:36 +04:00
2005-10-28 17:56:04 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2005-10-28 17:56:04 +04:00
void oprofile_arch_exit ( void )
2005-04-17 02:20:36 +04:00
{
2005-10-28 17:54:21 +04:00
if ( op_arm_model ) {
2005-04-17 02:20:36 +04:00
exit_driverfs ( ) ;
2005-10-28 17:54:21 +04:00
op_arm_model = NULL ;
2005-04-17 02:20:36 +04:00
}
}