2005-04-17 02:20:36 +04:00
/**
* @ file timer_int . c
*
* @ remark Copyright 2002 OProfile authors
* @ remark Read the file COPYING
*
* @ author John Levon < levon @ movementarian . org >
*/
# include <linux/kernel.h>
# include <linux/notifier.h>
# include <linux/smp.h>
# include <linux/oprofile.h>
# include <linux/profile.h>
# include <linux/init.h>
2010-03-02 18:01:10 +03:00
# include <linux/cpu.h>
# include <linux/hrtimer.h>
# include <asm/irq_regs.h>
2005-04-17 02:20:36 +04:00
# include <asm/ptrace.h>
# include "oprof.h"
2010-03-02 18:01:10 +03:00
static DEFINE_PER_CPU ( struct hrtimer , oprofile_hrtimer ) ;
2010-10-27 19:17:15 +04:00
static int ctr_running ;
2010-03-02 18:01:10 +03:00
static enum hrtimer_restart oprofile_hrtimer_notify ( struct hrtimer * hrtimer )
{
oprofile_add_sample ( get_irq_regs ( ) , 0 ) ;
hrtimer_forward_now ( hrtimer , ns_to_ktime ( TICK_NSEC ) ) ;
return HRTIMER_RESTART ;
}
static void __oprofile_hrtimer_start ( void * unused )
{
struct hrtimer * hrtimer = & __get_cpu_var ( oprofile_hrtimer ) ;
2010-10-27 19:17:15 +04:00
if ( ! ctr_running )
return ;
2010-03-02 18:01:10 +03:00
hrtimer_init ( hrtimer , CLOCK_MONOTONIC , HRTIMER_MODE_REL ) ;
hrtimer - > function = oprofile_hrtimer_notify ;
hrtimer_start ( hrtimer , ns_to_ktime ( TICK_NSEC ) ,
HRTIMER_MODE_REL_PINNED ) ;
}
static int oprofile_hrtimer_start ( void )
2005-04-17 02:20:36 +04:00
{
2010-10-27 19:17:15 +04:00
get_online_cpus ( ) ;
ctr_running = 1 ;
2010-03-02 18:01:10 +03:00
on_each_cpu ( __oprofile_hrtimer_start , NULL , 1 ) ;
2010-10-27 19:17:15 +04:00
put_online_cpus ( ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2010-03-02 18:01:10 +03:00
static void __oprofile_hrtimer_stop ( int cpu )
2005-04-17 02:20:36 +04:00
{
2010-03-02 18:01:10 +03:00
struct hrtimer * hrtimer = & per_cpu ( oprofile_hrtimer , cpu ) ;
2010-10-27 19:17:15 +04:00
if ( ! ctr_running )
return ;
2010-03-02 18:01:10 +03:00
hrtimer_cancel ( hrtimer ) ;
2005-04-17 02:20:36 +04:00
}
2010-03-02 18:01:10 +03:00
static void oprofile_hrtimer_stop ( void )
{
int cpu ;
2010-10-27 19:17:15 +04:00
get_online_cpus ( ) ;
2010-03-02 18:01:10 +03:00
for_each_online_cpu ( cpu )
__oprofile_hrtimer_stop ( cpu ) ;
2010-10-27 19:17:15 +04:00
ctr_running = 0 ;
put_online_cpus ( ) ;
2010-03-02 18:01:10 +03:00
}
2005-04-17 02:20:36 +04:00
2010-03-02 18:01:10 +03:00
static int __cpuinit oprofile_cpu_notify ( struct notifier_block * self ,
unsigned long action , void * hcpu )
2005-04-17 02:20:36 +04:00
{
2010-03-02 18:01:10 +03:00
long cpu = ( long ) hcpu ;
switch ( action ) {
case CPU_ONLINE :
case CPU_ONLINE_FROZEN :
smp_call_function_single ( cpu , __oprofile_hrtimer_start ,
NULL , 1 ) ;
break ;
case CPU_DEAD :
case CPU_DEAD_FROZEN :
__oprofile_hrtimer_stop ( cpu ) ;
break ;
}
return NOTIFY_OK ;
2005-04-17 02:20:36 +04:00
}
2010-03-02 18:01:10 +03:00
static struct notifier_block __refdata oprofile_cpu_notifier = {
. notifier_call = oprofile_cpu_notify ,
} ;
2005-04-17 02:20:36 +04:00
2011-02-11 19:31:44 +03:00
int oprofile_timer_init ( struct oprofile_operations * ops )
2005-04-17 02:20:36 +04:00
{
2010-03-02 18:01:10 +03:00
int rc ;
rc = register_hotcpu_notifier ( & oprofile_cpu_notifier ) ;
if ( rc )
return rc ;
2011-02-11 19:31:44 +03:00
ops - > create_files = NULL ;
2005-04-17 02:20:36 +04:00
ops - > setup = NULL ;
ops - > shutdown = NULL ;
2010-03-02 18:01:10 +03:00
ops - > start = oprofile_hrtimer_start ;
ops - > stop = oprofile_hrtimer_stop ;
2005-04-17 02:20:36 +04:00
ops - > cpu_type = " timer " ;
2010-03-02 18:01:10 +03:00
return 0 ;
}
2011-02-11 19:31:44 +03:00
void oprofile_timer_exit ( void )
2010-03-02 18:01:10 +03:00
{
unregister_hotcpu_notifier ( & oprofile_cpu_notifier ) ;
2005-04-17 02:20:36 +04:00
}