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;
  32
  33static void ppro_fill_in_addresses(struct op_msrs * const msrs)
  34{
  35        int i;
  36
  37        for (i = 0; i < num_counters; i++) {
  38                if (reserve_perfctr_nmi(MSR_P6_PERFCTR0 + i))
  39                        msrs->counters[i].addr = MSR_P6_PERFCTR0 + i;
  40                else
  41                        msrs->counters[i].addr = 0;
  42        }
  43
  44        for (i = 0; i < num_counters; i++) {
  45                if (reserve_evntsel_nmi(MSR_P6_EVNTSEL0 + i))
  46                        msrs->controls[i].addr = MSR_P6_EVNTSEL0 + i;
  47                else
  48                        msrs->controls[i].addr = 0;
  49        }
  50}
  51
  52
  53static void ppro_setup_ctrs(struct op_x86_model_spec const *model,
  54                            struct op_msrs const * const msrs)
  55{
  56        u64 val;
  57        int i;
  58
  59        if (!reset_value) {
  60                reset_value = kmalloc(sizeof(reset_value[0]) * num_counters,
  61                                        GFP_ATOMIC);
  62                if (!reset_value)
  63                        return;
  64        }
  65
  66        if (cpu_has_arch_perfmon) {
  67                union cpuid10_eax eax;
  68                eax.full = cpuid_eax(0xa);
  69
  70                /*
  71                 * For Core2 (family 6, model 15), don't reset the
  72                 * counter width:
  73                 */
  74                if (!(eax.split.version_id == 0 &&
  75                        current_cpu_data.x86 == 6 &&
  76                                current_cpu_data.x86_model == 15)) {
  77
  78                        if (counter_width < eax.split.bit_width)
  79                                counter_width = eax.split.bit_width;
  80                }
  81        }
  82
  83        /* clear all counters */
  84        for (i = 0; i < num_counters; ++i) {
  85                if (unlikely(!msrs->controls[i].addr))
  86                        continue;
  87                rdmsrl(msrs->controls[i].addr, val);
  88                val &= model->reserved;
  89                wrmsrl(msrs->controls[i].addr, val);
  90        }
  91
  92        /* avoid a false detection of ctr overflows in NMI handler */
  93        for (i = 0; i < num_counters; ++i) {
  94                if (unlikely(!msrs->counters[i].addr))
  95                        continue;
  96                wrmsrl(msrs->counters[i].addr, -1LL);
  97        }
  98
  99        /* enable active counters */
 100        for (i = 0; i < num_counters; ++i) {
 101                if (counter_config[i].enabled && msrs->counters[i].addr) {
 102                        reset_value[i] = counter_config[i].count;
 103                        wrmsrl(msrs->counters[i].addr, -reset_value[i]);
 104                        rdmsrl(msrs->controls[i].addr, val);
 105                        val &= model->reserved;
 106                        val |= op_x86_get_ctrl(model, &counter_config[i]);
 107                        wrmsrl(msrs->controls[i].addr, val);
 108                } else {
 109                        reset_value[i] = 0;
 110                }
 111        }
 112}
 113
 114
 115static int ppro_check_ctrs(struct pt_regs * const regs,
 116                           struct op_msrs const * const msrs)
 117{
 118        u64 val;
 119        int i;
 120
 121        /*
 122         * This can happen if perf counters are in use when
 123         * we steal the die notifier NMI.
 124         */
 125        if (unlikely(!reset_value))
 126                goto out;
 127
 128        for (i = 0; i < num_counters; ++i) {
 129                if (!reset_value[i])
 130                        continue;
 131                rdmsrl(msrs->counters[i].addr, val);
 132                if (val & (1ULL << (counter_width - 1)))
 133                        continue;
 134                oprofile_add_sample(regs, i);
 135                wrmsrl(msrs->counters[i].addr, -reset_value[i]);
 136        }
 137
 138out:
 139        /* Only P6 based Pentium M need to re-unmask the apic vector but it
 140         * doesn't hurt other P6 variant */
 141        apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
 142
 143        /* We can't work out if we really handled an interrupt. We
 144         * might have caught a *second* counter just after overflowing
 145         * the interrupt for this counter then arrives
 146         * and we don't find a counter that's overflowed, so we
 147         * would return 0 and get dazed + confused. Instead we always
 148         * assume we found an overflow. This sucks.
 149         */
 150        return 1;
 151}
 152
 153
 154static void ppro_start(struct op_msrs const * const msrs)
 155{
 156        u64 val;
 157        int i;
 158
 159        if (!reset_value)
 160                return;
 161        for (i = 0; i < num_counters; ++i) {
 162                if (reset_value[i]) {
 163                        rdmsrl(msrs->controls[i].addr, val);
 164                        val |= ARCH_PERFMON_EVENTSEL0_ENABLE;
 165                        wrmsrl(msrs->controls[i].addr, val);
 166                }
 167        }
 168}
 169
 170
 171static void ppro_stop(struct op_msrs const * const msrs)
 172{
 173        u64 val;
 174        int i;
 175
 176        if (!reset_value)
 177                return;
 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_EVENTSEL0_ENABLE;
 183                wrmsrl(msrs->controls[i].addr, val);
 184        }
 185}
 186
 187static void ppro_shutdown(struct op_msrs const * const msrs)
 188{
 189        int i;
 190
 191        for (i = 0; i < num_counters; ++i) {
 192                if (msrs->counters[i].addr)
 193                        release_perfctr_nmi(MSR_P6_PERFCTR0 + i);
 194        }
 195        for (i = 0; i < num_counters; ++i) {
 196                if (msrs->controls[i].addr)
 197                        release_evntsel_nmi(MSR_P6_EVNTSEL0 + i);
 198        }
 199        if (reset_value) {
 200                kfree(reset_value);
 201                reset_value = NULL;
 202        }
 203}
 204
 205
 206struct op_x86_model_spec op_ppro_spec = {
 207        .num_counters           = 2,
 208        .num_controls           = 2,
 209        .reserved               = MSR_PPRO_EVENTSEL_RESERVED,
 210        .fill_in_addresses      = &ppro_fill_in_addresses,
 211        .setup_ctrs             = &ppro_setup_ctrs,
 212        .check_ctrs             = &ppro_check_ctrs,
 213        .start                  = &ppro_start,
 214        .stop                   = &ppro_stop,
 215        .shutdown               = &ppro_shutdown
 216};
 217
 218/*
 219 * Architectural performance monitoring.
 220 *
 221 * Newer Intel CPUs (Core1+) have support for architectural
 222 * events described in CPUID 0xA. See the IA32 SDM Vol3b.18 for details.
 223 * The advantage of this is that it can be done without knowing about
 224 * the specific CPU.
 225 */
 226
 227static void arch_perfmon_setup_counters(void)
 228{
 229        union cpuid10_eax eax;
 230
 231        eax.full = cpuid_eax(0xa);
 232
 233        /* Workaround for BIOS bugs in 6/15. Taken from perfmon2 */
 234        if (eax.split.version_id == 0 && current_cpu_data.x86 == 6 &&
 235                current_cpu_data.x86_model == 15) {
 236                eax.split.version_id = 2;
 237                eax.split.num_events = 2;
 238                eax.split.bit_width = 40;
 239        }
 240
 241        num_counters = eax.split.num_events;
 242
 243        op_arch_perfmon_spec.num_counters = num_counters;
 244        op_arch_perfmon_spec.num_controls = num_counters;
 245}
 246
 247static int arch_perfmon_init(struct oprofile_operations *ignore)
 248{
 249        arch_perfmon_setup_counters();
 250        return 0;
 251}
 252
 253struct op_x86_model_spec op_arch_perfmon_spec = {
 254        .reserved               = MSR_PPRO_EVENTSEL_RESERVED,
 255        .init                   = &arch_perfmon_init,
 256        /* num_counters/num_controls filled in at runtime */
 257        .fill_in_addresses      = &ppro_fill_in_addresses,
 258        /* user space does the cpuid check for available events */
 259        .setup_ctrs             = &ppro_setup_ctrs,
 260        .check_ctrs             = &ppro_check_ctrs,
 261        .start                  = &ppro_start,
 262        .stop                   = &ppro_stop,
 263        .shutdown               = &ppro_shutdown
 264};
 265
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.