Path: blob/master/arch/x86/oprofile/op_model_ppro.c
10820 views
/*1* @file op_model_ppro.h2* Family 6 perfmon and architectural perfmon MSR operations3*4* @remark Copyright 2002 OProfile authors5* @remark Copyright 2008 Intel Corporation6* @remark Read the file COPYING7*8* @author John Levon9* @author Philippe Elie10* @author Graydon Hoare11* @author Andi Kleen12* @author Robert Richter <[email protected]>13*/1415#include <linux/oprofile.h>16#include <linux/slab.h>17#include <asm/ptrace.h>18#include <asm/msr.h>19#include <asm/apic.h>20#include <asm/nmi.h>2122#include "op_x86_model.h"23#include "op_counter.h"2425static int num_counters = 2;26static int counter_width = 32;2728#define MSR_PPRO_EVENTSEL_RESERVED ((0xFFFFFFFFULL<<32)|(1ULL<<21))2930static u64 *reset_value;3132static void ppro_shutdown(struct op_msrs const * const msrs)33{34int i;3536for (i = 0; i < num_counters; ++i) {37if (!msrs->counters[i].addr)38continue;39release_perfctr_nmi(MSR_P6_PERFCTR0 + i);40release_evntsel_nmi(MSR_P6_EVNTSEL0 + i);41}42if (reset_value) {43kfree(reset_value);44reset_value = NULL;45}46}4748static int ppro_fill_in_addresses(struct op_msrs * const msrs)49{50int i;5152for (i = 0; i < num_counters; i++) {53if (!reserve_perfctr_nmi(MSR_P6_PERFCTR0 + i))54goto fail;55if (!reserve_evntsel_nmi(MSR_P6_EVNTSEL0 + i)) {56release_perfctr_nmi(MSR_P6_PERFCTR0 + i);57goto fail;58}59/* both registers must be reserved */60msrs->counters[i].addr = MSR_P6_PERFCTR0 + i;61msrs->controls[i].addr = MSR_P6_EVNTSEL0 + i;62continue;63fail:64if (!counter_config[i].enabled)65continue;66op_x86_warn_reserved(i);67ppro_shutdown(msrs);68return -EBUSY;69}7071return 0;72}737475static void ppro_setup_ctrs(struct op_x86_model_spec const *model,76struct op_msrs const * const msrs)77{78u64 val;79int i;8081if (!reset_value) {82reset_value = kzalloc(sizeof(reset_value[0]) * num_counters,83GFP_ATOMIC);84if (!reset_value)85return;86}8788if (cpu_has_arch_perfmon) {89union cpuid10_eax eax;90eax.full = cpuid_eax(0xa);9192/*93* For Core2 (family 6, model 15), don't reset the94* counter width:95*/96if (!(eax.split.version_id == 0 &&97__this_cpu_read(cpu_info.x86) == 6 &&98__this_cpu_read(cpu_info.x86_model) == 15)) {99100if (counter_width < eax.split.bit_width)101counter_width = eax.split.bit_width;102}103}104105/* clear all counters */106for (i = 0; i < num_counters; ++i) {107if (!msrs->controls[i].addr)108continue;109rdmsrl(msrs->controls[i].addr, val);110if (val & ARCH_PERFMON_EVENTSEL_ENABLE)111op_x86_warn_in_use(i);112val &= model->reserved;113wrmsrl(msrs->controls[i].addr, val);114/*115* avoid a false detection of ctr overflows in NMI *116* handler117*/118wrmsrl(msrs->counters[i].addr, -1LL);119}120121/* enable active counters */122for (i = 0; i < num_counters; ++i) {123if (counter_config[i].enabled && msrs->counters[i].addr) {124reset_value[i] = counter_config[i].count;125wrmsrl(msrs->counters[i].addr, -reset_value[i]);126rdmsrl(msrs->controls[i].addr, val);127val &= model->reserved;128val |= op_x86_get_ctrl(model, &counter_config[i]);129wrmsrl(msrs->controls[i].addr, val);130} else {131reset_value[i] = 0;132}133}134}135136137static int ppro_check_ctrs(struct pt_regs * const regs,138struct op_msrs const * const msrs)139{140u64 val;141int i;142143/*144* This can happen if perf counters are in use when145* we steal the die notifier NMI.146*/147if (unlikely(!reset_value))148goto out;149150for (i = 0; i < num_counters; ++i) {151if (!reset_value[i])152continue;153rdmsrl(msrs->counters[i].addr, val);154if (val & (1ULL << (counter_width - 1)))155continue;156oprofile_add_sample(regs, i);157wrmsrl(msrs->counters[i].addr, -reset_value[i]);158}159160out:161/* Only P6 based Pentium M need to re-unmask the apic vector but it162* doesn't hurt other P6 variant */163apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);164165/* We can't work out if we really handled an interrupt. We166* might have caught a *second* counter just after overflowing167* the interrupt for this counter then arrives168* and we don't find a counter that's overflowed, so we169* would return 0 and get dazed + confused. Instead we always170* assume we found an overflow. This sucks.171*/172return 1;173}174175176static void ppro_start(struct op_msrs const * const msrs)177{178u64 val;179int i;180181if (!reset_value)182return;183for (i = 0; i < num_counters; ++i) {184if (reset_value[i]) {185rdmsrl(msrs->controls[i].addr, val);186val |= ARCH_PERFMON_EVENTSEL_ENABLE;187wrmsrl(msrs->controls[i].addr, val);188}189}190}191192193static void ppro_stop(struct op_msrs const * const msrs)194{195u64 val;196int i;197198if (!reset_value)199return;200for (i = 0; i < num_counters; ++i) {201if (!reset_value[i])202continue;203rdmsrl(msrs->controls[i].addr, val);204val &= ~ARCH_PERFMON_EVENTSEL_ENABLE;205wrmsrl(msrs->controls[i].addr, val);206}207}208209struct op_x86_model_spec op_ppro_spec = {210.num_counters = 2,211.num_controls = 2,212.reserved = MSR_PPRO_EVENTSEL_RESERVED,213.fill_in_addresses = &ppro_fill_in_addresses,214.setup_ctrs = &ppro_setup_ctrs,215.check_ctrs = &ppro_check_ctrs,216.start = &ppro_start,217.stop = &ppro_stop,218.shutdown = &ppro_shutdown219};220221/*222* Architectural performance monitoring.223*224* Newer Intel CPUs (Core1+) have support for architectural225* events described in CPUID 0xA. See the IA32 SDM Vol3b.18 for details.226* The advantage of this is that it can be done without knowing about227* the specific CPU.228*/229230static void arch_perfmon_setup_counters(void)231{232union cpuid10_eax eax;233234eax.full = cpuid_eax(0xa);235236/* Workaround for BIOS bugs in 6/15. Taken from perfmon2 */237if (eax.split.version_id == 0 && __this_cpu_read(cpu_info.x86) == 6 &&238__this_cpu_read(cpu_info.x86_model) == 15) {239eax.split.version_id = 2;240eax.split.num_counters = 2;241eax.split.bit_width = 40;242}243244num_counters = eax.split.num_counters;245246op_arch_perfmon_spec.num_counters = num_counters;247op_arch_perfmon_spec.num_controls = num_counters;248}249250static int arch_perfmon_init(struct oprofile_operations *ignore)251{252arch_perfmon_setup_counters();253return 0;254}255256struct op_x86_model_spec op_arch_perfmon_spec = {257.reserved = MSR_PPRO_EVENTSEL_RESERVED,258.init = &arch_perfmon_init,259/* num_counters/num_controls filled in at runtime */260.fill_in_addresses = &ppro_fill_in_addresses,261/* user space does the cpuid check for available events */262.setup_ctrs = &ppro_setup_ctrs,263.check_ctrs = &ppro_check_ctrs,264.start = &ppro_start,265.stop = &ppro_stop,266.shutdown = &ppro_shutdown267};268269270