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 = &__get_cpu_var(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_cpu_notify(struct notifier_block *self,
  78                               unsigned long action, void *hcpu)
  79{
  80        long cpu = (long) hcpu;
  81
  82        switch (action) {
  83        case CPU_ONLINE:
  84        case CPU_ONLINE_FROZEN:
  85                smp_call_function_single(cpu, __oprofile_hrtimer_start,
  86                                         NULL, 1);
  87                break;
  88        case CPU_DEAD:
  89        case CPU_DEAD_FROZEN:
  90                __oprofile_hrtimer_stop(cpu);
  91                break;
  92        }
  93        return NOTIFY_OK;
  94}
  95
  96static struct notifier_block __refdata oprofile_cpu_notifier = {
  97        .notifier_call = oprofile_cpu_notify,
  98};
  99
 100static int oprofile_hrtimer_setup(void)
 101{
 102        return register_hotcpu_notifier(&oprofile_cpu_notifier);
 103}
 104
 105static void oprofile_hrtimer_shutdown(void)
 106{
 107        unregister_hotcpu_notifier(&oprofile_cpu_notifier);
 108}
 109
 110int oprofile_timer_init(struct oprofile_operations *ops)
 111{
 112        ops->create_files       = NULL;
 113        ops->setup              = oprofile_hrtimer_setup;
 114        ops->shutdown           = oprofile_hrtimer_shutdown;
 115        ops->start              = oprofile_hrtimer_start;
 116        ops->stop               = oprofile_hrtimer_stop;
 117        ops->cpu_type           = "timer";
 118        printk(KERN_INFO "oprofile: using timer interrupt.\n");
 119        return 0;
 120}
 121