linux/drivers/oprofile/timer_int.c
<<
>>
Prefs
   1/**
   2 * @file timer_int.c
   3 *
   4 * @remark Copyright 2002 OProfile authors
   5 * @remark Read the file COPYING
   6 *
   7 * @author John Levon <levon@movementarian.org>
   8 */
   9
  10#include <linux/kernel.h>
  11#include <linux/notifier.h>
  12#include <linux/smp.h>
  13#include <linux/oprofile.h>
  14#include <linux/profile.h>
  15#include <linux/init.h>
  16#include <linux/cpu.h>
  17#include <linux/hrtimer.h>
  18#include <asm/irq_regs.h>
  19#include <asm/ptrace.h>
  20
  21#include "oprof.h"
  22
  23static DEFINE_PER_CPU(struct hrtimer, oprofile_hrtimer);
  24static int ctr_running;
  25
  26static enum hrtimer_restart oprofile_hrtimer_notify(struct hrtimer *hrtimer)
  27{
  28        oprofile_add_sample(get_irq_regs(), 0);
  29        hrtimer_forward_now(hrtimer, ns_to_ktime(TICK_NSEC));
  30        return HRTIMER_RESTART;
  31}
  32
  33static void __oprofile_hrtimer_start(void *unused)
  34{
  35        struct hrtimer *hrtimer = this_cpu_ptr(&oprofile_hrtimer);
  36
  37        if (!ctr_running)
  38                return;
  39
  40        hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
  41        hrtimer->function = oprofile_hrtimer_notify;
  42
  43        hrtimer_start(hrtimer, ns_to_ktime(TICK_NSEC),
  44                      HRTIMER_MODE_REL_PINNED);
  45}
  46
  47static int oprofile_hrtimer_start(void)
  48{
  49        get_online_cpus();
  50        ctr_running = 1;
  51        on_each_cpu(__oprofile_hrtimer_start, NULL, 1);
  52        put_online_cpus();
  53        return 0;
  54}
  55
  56static void __oprofile_hrtimer_stop(int cpu)
  57{
  58        struct hrtimer *hrtimer = &per_cpu(oprofile_hrtimer, cpu);
  59
  60        if (!ctr_running)
  61                return;
  62
  63        hrtimer_cancel(hrtimer);
  64}
  65
  66static void oprofile_hrtimer_stop(void)
  67{
  68        int cpu;
  69
  70        get_online_cpus();
  71        for_each_online_cpu(cpu)
  72                __oprofile_hrtimer_stop(cpu);
  73        ctr_running = 0;
  74        put_online_cpus();
  75}
  76
  77static int oprofile_timer_online(unsigned int cpu)
  78{
  79        local_irq_disable();
  80        __oprofile_hrtimer_start(NULL);
  81        local_irq_enable();
  82        return 0;
  83}
  84
  85static int oprofile_timer_prep_down(unsigned int cpu)
  86{
  87        __oprofile_hrtimer_stop(cpu);
  88        return 0;
  89}
  90
  91static enum cpuhp_state hp_online;
  92
  93static int oprofile_hrtimer_setup(void)
  94{
  95        int ret;
  96
  97        ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
  98                                        "oprofile/timer:online",
  99                                        oprofile_timer_online,
 100                                        oprofile_timer_prep_down);
 101        if (ret < 0)
 102                return ret;
 103        hp_online = ret;
 104        return 0;
 105}
 106
 107static void oprofile_hrtimer_shutdown(void)
 108{
 109        cpuhp_remove_state_nocalls(hp_online);
 110}
 111
 112int oprofile_timer_init(struct oprofile_operations *ops)
 113{
 114        ops->create_files       = NULL;
 115        ops->setup              = oprofile_hrtimer_setup;
 116        ops->shutdown           = oprofile_hrtimer_shutdown;
 117        ops->start              = oprofile_hrtimer_start;
 118        ops->stop               = oprofile_hrtimer_stop;
 119        ops->cpu_type           = "timer";
 120        printk(KERN_INFO "oprofile: using timer interrupt.\n");
 121        return 0;
 122}
 123