linux/arch/x86/oprofile/op_model_ppro.c
<<
>>
Prefs
   1/*
   2 * @file op_model_ppro.h
   3 * Family 6 perfmon and architectural perfmon MSR operations
   4 *
   5 * @remark Copyright 2002 OProfile authors
   6 * @remark Copyright 2008 Intel Corporation
   7 * @remark Read the file COPYING
   8 *
   9 * @author John Levon
  10 * @author Philippe Elie
  11 * @author Graydon Hoare
  12 * @author Andi Kleen
  13 * @author Robert Richter <robert.richter@amd.com>
  14 */
  15
  16#include <linux/oprofile.h>
  17#include <linux/slab.h>
  18#include <asm/ptrace.h>
  19#include <asm/msr.h>
  20#include <asm/apic.h>
  21#include <asm/nmi.h>
  22
  23#include "op_x86_model.h"
  24#include "op_counter.h"
  25
  26static int num_counters = 2;
  27static int counter_width = 32;
  28
  29#define MSR_PPRO_EVENTSEL_RESERVED      ((0xFFFFFFFFULL<<32)|(1ULL<<21))
  30
  31static u64 reset_value[OP_MAX_COUNTER];
  32
  33static void ppro_shutdown(struct op_msrs const * const msrs)
  34{
  35        int i;
  36
  37        for (i = 0; i < num_counters; ++i) {
  38                if (!msrs->counters[i].addr)
  39                        continue;
  40                release_perfctr_nmi(MSR_P6_PERFCTR0 + i);
  41                release_evntsel_nmi(MSR_P6_EVNTSEL0 + i);
  42        }
  43}
  44
  45static int ppro_fill_in_addresses(struct op_msrs * const msrs)
  46{
  47        int i;
  48
  49        for (i = 0; i < num_counters; i++) {
  50                if (!reserve_perfctr_nmi(MSR_P6_PERFCTR0 + i))
  51                        goto fail;
  52                if (!reserve_evntsel_nmi(MSR_P6_EVNTSEL0 + i)) {
  53                        release_perfctr_nmi(MSR_P6_PERFCTR0 + i);
  54                        goto fail;
  55                }
  56                /* both registers must be reserved */
  57                msrs->counters[i].addr = MSR_P6_PERFCTR0 + i;
  58                msrs->controls[i].addr = MSR_P6_EVNTSEL0 + i;
  59                continue;
  60        fail:
  61                if (!counter_config[i].enabled)
  62                        continue;
  63                op_x86_warn_reserved(i);
  64                ppro_shutdown(msrs);
  65                return -EBUSY;
  66        }
  67
  68        return 0;
  69}
  70
  71
  72static void ppro_setup_ctrs(struct op_x86_model_spec const *model,
  73                            struct op_msrs const * const msrs)
  74{
  75        u64 val;
  76        int i;
  77
  78        if (boot_cpu_has(X86_FEATURE_ARCH_PERFMON)) {
  79                union cpuid10_eax eax;
  80                eax.full = cpuid_eax(0xa);
  81
  82                /*
  83                 * For Core2 (family 6, model 15), don't reset the
  84                 * counter width:
  85                 */
  86                if (!(eax.split.version_id == 0 &&
  87                        __this_cpu_read(cpu_info.x86) == 6 &&
  88                                __this_cpu_read(cpu_info.x86_model) == 15)) {
  89
  90                        if (counter_width < eax.split.bit_width)
  91                                counter_width = eax.split.bit_width;
  92                }
  93        }
  94
  95        /* clear all counters */
  96        for (i = 0; i < num_counters; ++i) {
  97                if (!msrs->controls[i].addr)
  98                        continue;
  99                rdmsrl(msrs->controls[i].addr, val);
 100                if (val & ARCH_PERFMON_EVENTSEL_ENABLE)
 101                        op_x86_warn_in_use(i);
 102                val &= model->reserved;
 103                wrmsrl(msrs->controls[i].addr, val);
 104                /*
 105                 * avoid a false detection of ctr overflows in NMI *
 106                 * handler
 107                 */
 108                wrmsrl(msrs->counters[i].addr, -1LL);
 109        }
 110
 111        /* enable active counters */
 112        for (i = 0; i < num_counters; ++i) {
 113                if (counter_config[i].enabled && msrs->counters[i].addr) {
 114                        reset_value[i] = counter_config[i].count;
 115                        wrmsrl(msrs->counters[i].addr, -reset_value[i]);
 116                        rdmsrl(msrs->controls[i].addr, val);
 117                        val &= model->reserved;
 118                        val |= op_x86_get_ctrl(model, &counter_config[i]);
 119                        wrmsrl(msrs->controls[i].addr, val);
 120                } else {
 121                        reset_value[i] = 0;
 122                }
 123        }
 124}
 125
 126
 127static int ppro_check_ctrs(struct pt_regs * const regs,
 128                           struct op_msrs const * const msrs)
 129{
 130        u64 val;
 131        int i;
 132
 133        for (i = 0; i < num_counters; ++i) {
 134                if (!reset_value[i])
 135                        continue;
 136                rdmsrl(msrs->counters[i].addr, val);
 137                if (val & (1ULL << (counter_width - 1)))
 138                        continue;
 139                oprofile_add_sample(regs, i);
 140                wrmsrl(msrs->counters[i].addr, -reset_value[i]);
 141        }
 142
 143        /* Only P6 based Pentium M need to re-unmask the apic vector but it
 144         * doesn't hurt other P6 variant */
 145        apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
 146
 147        /* We can't work out if we really handled an interrupt. We
 148         * might have caught a *second* counter just after overflowing
 149         * the interrupt for this counter then arrives
 150         * and we don't find a counter that's overflowed, so we
 151         * would return 0 and get dazed + confused. Instead we always
 152         * assume we found an overflow. This sucks.
 153         */
 154        return 1;
 155}
 156
 157
 158static void ppro_start(struct op_msrs const * const msrs)
 159{
 160        u64 val;
 161        int i;
 162
 163        for (i = 0; i < num_counters; ++i) {
 164                if (reset_value[i]) {
 165                        rdmsrl(msrs->controls[i].addr, val);
 166                        val |= ARCH_PERFMON_EVENTSEL_ENABLE;
 167                        wrmsrl(msrs->controls[i].addr, val);
 168                }
 169        }
 170}
 171
 172
 173static void ppro_stop(struct op_msrs const * const msrs)
 174{
 175        u64 val;
 176        int i;
 177
 178        for (i = 0; i < num_counters; ++i) {
 179                if (!reset_value[i])
 180                        continue;
 181                rdmsrl(msrs->controls[i].addr, val);
 182                val &= ~ARCH_PERFMON_EVENTSEL_ENABLE;
 183                wrmsrl(msrs->controls[i].addr, val);
 184        }
 185}
 186
 187struct op_x86_model_spec op_ppro_spec = {
 188        .num_counters           = 2,
 189        .num_controls           = 2,
 190        .reserved               = MSR_PPRO_EVENTSEL_RESERVED,
 191        .fill_in_addresses      = &ppro_fill_in_addresses,
 192        .setup_ctrs             = &ppro_setup_ctrs,
 193        .check_ctrs             = &ppro_check_ctrs,
 194        .start                  = &ppro_start,
 195        .stop                   = &ppro_stop,
 196        .shutdown               = &ppro_shutdown
 197};
 198
 199/*
 200 * Architectural performance monitoring.
 201 *
 202 * Newer Intel CPUs (Core1+) have support for architectural
 203 * events described in CPUID 0xA. See the IA32 SDM Vol3b.18 for details.
 204 * The advantage of this is that it can be done without knowing about
 205 * the specific CPU.
 206 */
 207
 208static void arch_perfmon_setup_counters(void)
 209{
 210        union cpuid10_eax eax;
 211
 212        eax.full = cpuid_eax(0xa);
 213
 214        /* Workaround for BIOS bugs in 6/15. Taken from perfmon2 */
 215        if (eax.split.version_id == 0 && boot_cpu_data.x86 == 6 &&
 216            boot_cpu_data.x86_model == 15) {
 217                eax.split.version_id = 2;
 218                eax.split.num_counters = 2;
 219                eax.split.bit_width = 40;
 220        }
 221
 222        num_counters = min((int)eax.split.num_counters, OP_MAX_COUNTER);
 223
 224        op_arch_perfmon_spec.num_counters = num_counters;
 225        op_arch_perfmon_spec.num_controls = num_counters;
 226}
 227
 228static int arch_perfmon_init(struct oprofile_operations *ignore)
 229{
 230        arch_perfmon_setup_counters();
 231        return 0;
 232}
 233
 234struct op_x86_model_spec op_arch_perfmon_spec = {
 235        .reserved               = MSR_PPRO_EVENTSEL_RESERVED,
 236        .init                   = &arch_perfmon_init,
 237        /* num_counters/num_controls filled in at runtime */
 238        .fill_in_addresses      = &ppro_fill_in_addresses,
 239        /* user space does the cpuid check for available events */
 240        .setup_ctrs             = &ppro_setup_ctrs,
 241        .check_ctrs             = &ppro_check_ctrs,
 242        .start                  = &ppro_start,
 243        .stop                   = &ppro_stop,
 244        .shutdown               = &ppro_shutdown
 245};
 246