2006-10-17 19:21:48 -07:00
/**
* @ file init . c
*
* @ remark Copyright 2002 OProfile authors
* @ remark Read the file COPYING
*
* @ author John Levon < levon @ movementarian . org >
*/
# include <linux/kernel.h>
# include <linux/oprofile.h>
# include <linux/errno.h>
# include <linux/init.h>
2009-10-05 00:46:08 -07:00
# include <linux/param.h> /* for HZ */
2006-10-17 19:21:48 -07:00
2008-11-25 22:29:24 -08:00
# ifdef CONFIG_SPARC64
2009-01-29 21:22:47 -08:00
# include <linux/notifier.h>
# include <linux/rcupdate.h>
# include <linux/kdebug.h>
# include <asm/nmi.h>
2008-11-25 22:29:24 -08:00
2009-01-29 21:22:47 -08:00
static int profile_timer_exceptions_notify ( struct notifier_block * self ,
unsigned long val , void * data )
2008-11-25 22:29:24 -08:00
{
2009-09-08 23:20:39 -07:00
struct die_args * args = data ;
2009-01-29 21:22:47 -08:00
int ret = NOTIFY_DONE ;
2008-11-25 22:29:24 -08:00
2009-01-29 21:22:47 -08:00
switch ( val ) {
case DIE_NMI :
oprofile_add_sample ( args - > regs , 0 ) ;
ret = NOTIFY_STOP ;
break ;
default :
break ;
2008-11-25 22:29:24 -08:00
}
2009-01-29 21:22:47 -08:00
return ret ;
2008-11-25 22:29:24 -08:00
}
2009-01-29 21:22:47 -08:00
static struct notifier_block profile_timer_exceptions_nb = {
. notifier_call = profile_timer_exceptions_notify ,
} ;
2008-11-25 22:29:24 -08:00
2009-01-29 21:22:47 -08:00
static int timer_start ( void )
2008-11-25 22:29:24 -08:00
{
2009-01-29 21:22:47 -08:00
if ( register_die_notifier ( & profile_timer_exceptions_nb ) )
return 1 ;
nmi_adjust_hz ( HZ ) ;
return 0 ;
2008-11-25 22:29:24 -08:00
}
2009-01-29 21:22:47 -08:00
static void timer_stop ( void )
2008-11-25 22:29:24 -08:00
{
2009-01-29 21:22:47 -08:00
nmi_adjust_hz ( 1 ) ;
unregister_die_notifier ( & profile_timer_exceptions_nb ) ;
synchronize_sched ( ) ; /* Allow already-started NMIs to complete. */
2008-11-25 22:29:24 -08:00
}
2009-01-29 21:22:47 -08:00
static int op_nmi_timer_init ( struct oprofile_operations * ops )
2008-11-25 22:29:24 -08:00
{
2009-09-08 23:16:06 -07:00
if ( atomic_read ( & nmi_active ) < = 0 )
2008-11-25 22:29:24 -08:00
return - ENODEV ;
2009-01-29 21:22:47 -08:00
ops - > start = timer_start ;
ops - > stop = timer_stop ;
2008-11-25 22:29:24 -08:00
ops - > cpu_type = " timer " ;
2009-01-29 21:22:47 -08:00
printk ( KERN_INFO " oprofile: Using perfctr NMI timer interrupt. \n " ) ;
2008-11-25 22:29:24 -08:00
return 0 ;
}
# endif
2008-09-05 17:12:36 +02:00
int __init oprofile_arch_init ( struct oprofile_operations * ops )
2006-10-17 19:21:48 -07:00
{
2008-11-25 22:29:24 -08:00
int ret = - ENODEV ;
# ifdef CONFIG_SPARC64
2009-01-29 21:22:47 -08:00
ret = op_nmi_timer_init ( ops ) ;
2008-11-25 22:29:24 -08:00
if ( ! ret )
return ret ;
# endif
return ret ;
2006-10-17 19:21:48 -07:00
}
void oprofile_arch_exit ( void )
{
}