root/drivers/oprofile/nmi_timer_int.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nmi_timer_callback
  2. nmi_timer_start_cpu
  3. nmi_timer_stop_cpu
  4. nmi_timer_cpu_online
  5. nmi_timer_cpu_predown
  6. nmi_timer_start
  7. nmi_timer_stop
  8. nmi_timer_shutdown
  9. nmi_timer_setup
  10. op_nmi_timer_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /**
   3  * @file nmi_timer_int.c
   4  *
   5  * @remark Copyright 2011 Advanced Micro Devices, Inc.
   6  *
   7  * @author Robert Richter <robert.richter@amd.com>
   8  */
   9 
  10 #include <linux/init.h>
  11 #include <linux/smp.h>
  12 #include <linux/errno.h>
  13 #include <linux/oprofile.h>
  14 #include <linux/perf_event.h>
  15 
  16 #ifdef CONFIG_OPROFILE_NMI_TIMER
  17 
  18 static DEFINE_PER_CPU(struct perf_event *, nmi_timer_events);
  19 static int ctr_running;
  20 
  21 static struct perf_event_attr nmi_timer_attr = {
  22         .type           = PERF_TYPE_HARDWARE,
  23         .config         = PERF_COUNT_HW_CPU_CYCLES,
  24         .size           = sizeof(struct perf_event_attr),
  25         .pinned         = 1,
  26         .disabled       = 1,
  27 };
  28 
  29 static void nmi_timer_callback(struct perf_event *event,
  30                                struct perf_sample_data *data,
  31                                struct pt_regs *regs)
  32 {
  33         event->hw.interrupts = 0;       /* don't throttle interrupts */
  34         oprofile_add_sample(regs, 0);
  35 }
  36 
  37 static int nmi_timer_start_cpu(int cpu)
  38 {
  39         struct perf_event *event = per_cpu(nmi_timer_events, cpu);
  40 
  41         if (!event) {
  42                 event = perf_event_create_kernel_counter(&nmi_timer_attr, cpu, NULL,
  43                                                          nmi_timer_callback, NULL);
  44                 if (IS_ERR(event))
  45                         return PTR_ERR(event);
  46                 per_cpu(nmi_timer_events, cpu) = event;
  47         }
  48 
  49         if (event && ctr_running)
  50                 perf_event_enable(event);
  51 
  52         return 0;
  53 }
  54 
  55 static void nmi_timer_stop_cpu(int cpu)
  56 {
  57         struct perf_event *event = per_cpu(nmi_timer_events, cpu);
  58 
  59         if (event && ctr_running)
  60                 perf_event_disable(event);
  61 }
  62 
  63 static int nmi_timer_cpu_online(unsigned int cpu)
  64 {
  65         nmi_timer_start_cpu(cpu);
  66         return 0;
  67 }
  68 static int nmi_timer_cpu_predown(unsigned int cpu)
  69 {
  70         nmi_timer_stop_cpu(cpu);
  71         return 0;
  72 }
  73 
  74 static int nmi_timer_start(void)
  75 {
  76         int cpu;
  77 
  78         get_online_cpus();
  79         ctr_running = 1;
  80         for_each_online_cpu(cpu)
  81                 nmi_timer_start_cpu(cpu);
  82         put_online_cpus();
  83 
  84         return 0;
  85 }
  86 
  87 static void nmi_timer_stop(void)
  88 {
  89         int cpu;
  90 
  91         get_online_cpus();
  92         for_each_online_cpu(cpu)
  93                 nmi_timer_stop_cpu(cpu);
  94         ctr_running = 0;
  95         put_online_cpus();
  96 }
  97 
  98 static enum cpuhp_state hp_online;
  99 
 100 static void nmi_timer_shutdown(void)
 101 {
 102         struct perf_event *event;
 103         int cpu;
 104 
 105         cpuhp_remove_state(hp_online);
 106         for_each_possible_cpu(cpu) {
 107                 event = per_cpu(nmi_timer_events, cpu);
 108                 if (!event)
 109                         continue;
 110                 perf_event_disable(event);
 111                 per_cpu(nmi_timer_events, cpu) = NULL;
 112                 perf_event_release_kernel(event);
 113         }
 114 }
 115 
 116 static int nmi_timer_setup(void)
 117 {
 118         int err;
 119         u64 period;
 120 
 121         /* clock cycles per tick: */
 122         period = (u64)cpu_khz * 1000;
 123         do_div(period, HZ);
 124         nmi_timer_attr.sample_period = period;
 125 
 126         err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "oprofile/nmi:online",
 127                                 nmi_timer_cpu_online, nmi_timer_cpu_predown);
 128         if (err < 0) {
 129                 nmi_timer_shutdown();
 130                 return err;
 131         }
 132         hp_online = err;
 133         return 0;
 134 }
 135 
 136 int __init op_nmi_timer_init(struct oprofile_operations *ops)
 137 {
 138         int err = 0;
 139 
 140         err = nmi_timer_setup();
 141         if (err)
 142                 return err;
 143         nmi_timer_shutdown();           /* only check, don't alloc */
 144 
 145         ops->create_files       = NULL;
 146         ops->setup              = nmi_timer_setup;
 147         ops->shutdown           = nmi_timer_shutdown;
 148         ops->start              = nmi_timer_start;
 149         ops->stop               = nmi_timer_stop;
 150         ops->cpu_type           = "timer";
 151 
 152         printk(KERN_INFO "oprofile: using NMI timer interrupt.\n");
 153 
 154         return 0;
 155 }
 156 
 157 #endif

/* [<][>][^][v][top][bottom][index][help] */