linux/arch/x86/kernel/cpu/perfctr-watchdog.c
<<
>>
Prefs
   1/*
   2 * local apic based NMI watchdog for various CPUs.
   3 *
   4 * This file also handles reservation of performance counters for coordination
   5 * with other users (like oprofile).
   6 *
   7 * Note that these events normally don't tick when the CPU idles. This means
   8 * the frequency varies with CPU load.
   9 *
  10 * Original code for K7/P6 written by Keith Owens
  11 *
  12 */
  13
  14#include <linux/percpu.h>
  15#include <linux/module.h>
  16#include <linux/kernel.h>
  17#include <linux/bitops.h>
  18#include <linux/smp.h>
  19#include <asm/nmi.h>
  20#include <linux/kprobes.h>
  21
  22#include <asm/apic.h>
  23#include <asm/perf_event.h>
  24
  25/*
  26 * this number is calculated from Intel's MSR_P4_CRU_ESCR5 register and it's
  27 * offset from MSR_P4_BSU_ESCR0.
  28 *
  29 * It will be the max for all platforms (for now)
  30 */
  31#define NMI_MAX_COUNTER_BITS 66
  32
  33/*
  34 * perfctr_nmi_owner tracks the ownership of the perfctr registers:
  35 * evtsel_nmi_owner tracks the ownership of the event selection
  36 * - different performance counters/ event selection may be reserved for
  37 *   different subsystems this reservation system just tries to coordinate
  38 *   things a little
  39 */
  40static DECLARE_BITMAP(perfctr_nmi_owner, NMI_MAX_COUNTER_BITS);
  41static DECLARE_BITMAP(evntsel_nmi_owner, NMI_MAX_COUNTER_BITS);
  42
  43/* converts an msr to an appropriate reservation bit */
  44static inline unsigned int nmi_perfctr_msr_to_bit(unsigned int msr)
  45{
  46        /* returns the bit offset of the performance counter register */
  47        switch (boot_cpu_data.x86_vendor) {
  48        case X86_VENDOR_AMD:
  49                return msr - MSR_K7_PERFCTR0;
  50        case X86_VENDOR_INTEL:
  51                if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
  52                        return msr - MSR_ARCH_PERFMON_PERFCTR0;
  53
  54                switch (boot_cpu_data.x86) {
  55                case 6:
  56                        return msr - MSR_P6_PERFCTR0;
  57                case 15:
  58                        return msr - MSR_P4_BPU_PERFCTR0;
  59                }
  60        }
  61        return 0;
  62}
  63
  64/*
  65 * converts an msr to an appropriate reservation bit
  66 * returns the bit offset of the event selection register
  67 */
  68static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr)
  69{
  70        /* returns the bit offset of the event selection register */
  71        switch (boot_cpu_data.x86_vendor) {
  72        case X86_VENDOR_AMD:
  73                return msr - MSR_K7_EVNTSEL0;
  74        case X86_VENDOR_INTEL:
  75                if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
  76                        return msr - MSR_ARCH_PERFMON_EVENTSEL0;
  77
  78                switch (boot_cpu_data.x86) {
  79                case 6:
  80                        return msr - MSR_P6_EVNTSEL0;
  81                case 15:
  82                        return msr - MSR_P4_BSU_ESCR0;
  83                }
  84        }
  85        return 0;
  86
  87}
  88
  89/* checks for a bit availability (hack for oprofile) */
  90int avail_to_resrv_perfctr_nmi_bit(unsigned int counter)
  91{
  92        BUG_ON(counter > NMI_MAX_COUNTER_BITS);
  93
  94        return !test_bit(counter, perfctr_nmi_owner);
  95}
  96EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi_bit);
  97
  98int reserve_perfctr_nmi(unsigned int msr)
  99{
 100        unsigned int counter;
 101
 102        counter = nmi_perfctr_msr_to_bit(msr);
 103        /* register not managed by the allocator? */
 104        if (counter > NMI_MAX_COUNTER_BITS)
 105                return 1;
 106
 107        if (!test_and_set_bit(counter, perfctr_nmi_owner))
 108                return 1;
 109        return 0;
 110}
 111EXPORT_SYMBOL(reserve_perfctr_nmi);
 112
 113void release_perfctr_nmi(unsigned int msr)
 114{
 115        unsigned int counter;
 116
 117        counter = nmi_perfctr_msr_to_bit(msr);
 118        /* register not managed by the allocator? */
 119        if (counter > NMI_MAX_COUNTER_BITS)
 120                return;
 121
 122        clear_bit(counter, perfctr_nmi_owner);
 123}
 124EXPORT_SYMBOL(release_perfctr_nmi);
 125
 126int reserve_evntsel_nmi(unsigned int msr)
 127{
 128        unsigned int counter;
 129
 130        counter = nmi_evntsel_msr_to_bit(msr);
 131        /* register not managed by the allocator? */
 132        if (counter > NMI_MAX_COUNTER_BITS)
 133                return 1;
 134
 135        if (!test_and_set_bit(counter, evntsel_nmi_owner))
 136                return 1;
 137        return 0;
 138}
 139EXPORT_SYMBOL(reserve_evntsel_nmi);
 140
 141void release_evntsel_nmi(unsigned int msr)
 142{
 143        unsigned int counter;
 144
 145        counter = nmi_evntsel_msr_to_bit(msr);
 146        /* register not managed by the allocator? */
 147        if (counter > NMI_MAX_COUNTER_BITS)
 148                return;
 149
 150        clear_bit(counter, evntsel_nmi_owner);
 151}
 152EXPORT_SYMBOL(release_evntsel_nmi);
 153