2005-04-16 15:20:36 -07:00
/**
* @ file nmi_timer_int . c
*
* @ remark Copyright 2003 OProfile authors
* @ remark Read the file COPYING
*
* @ author Zwane Mwaikambo < zwane @ linuxpower . ca >
*/
# include <linux/init.h>
# include <linux/smp.h>
2005-09-26 05:49:44 +01:00
# include <linux/errno.h>
2005-04-16 15:20:36 -07:00
# include <linux/oprofile.h>
# include <linux/rcupdate.h>
2007-05-08 00:27:03 -07:00
# include <linux/kdebug.h>
2005-04-16 15:20:36 -07:00
# include <asm/nmi.h>
# include <asm/apic.h>
# include <asm/ptrace.h>
2006-09-26 10:52:27 +02:00
static int profile_timer_exceptions_notify ( struct notifier_block * self ,
unsigned long val , void * data )
2005-04-16 15:20:36 -07:00
{
2006-09-26 10:52:27 +02:00
struct die_args * args = ( struct die_args * ) data ;
int ret = NOTIFY_DONE ;
switch ( val ) {
case DIE_NMI :
oprofile_add_sample ( args - > regs , 0 ) ;
ret = NOTIFY_STOP ;
break ;
default :
break ;
}
return ret ;
2005-04-16 15:20:36 -07:00
}
2006-09-26 10:52:27 +02:00
static struct notifier_block profile_timer_exceptions_nb = {
. notifier_call = profile_timer_exceptions_notify ,
. next = NULL ,
. priority = 0
} ;
2005-04-16 15:20:36 -07:00
static int timer_start ( void )
{
2006-09-26 10:52:27 +02:00
if ( register_die_notifier ( & profile_timer_exceptions_nb ) )
return 1 ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
static void timer_stop ( void )
{
2006-09-26 10:52:27 +02:00
unregister_die_notifier ( & profile_timer_exceptions_nb ) ;
2005-05-01 08:59:04 -07:00
synchronize_sched ( ) ; /* Allow already-started NMIs to complete. */
2005-04-16 15:20:36 -07:00
}
2005-09-06 15:17:26 -07:00
int __init op_nmi_timer_init ( struct oprofile_operations * ops )
2005-04-16 15:20:36 -07:00
{
2006-09-26 10:52:27 +02:00
if ( ( nmi_watchdog ! = NMI_IO_APIC ) | | ( atomic_read ( & nmi_active ) < = 0 ) )
2005-04-16 15:20:36 -07:00
return - ENODEV ;
ops - > start = timer_start ;
ops - > stop = timer_stop ;
ops - > cpu_type = " timer " ;
printk ( KERN_INFO " oprofile: using NMI timer interrupt. \n " ) ;
return 0 ;
}