Path: blob/master/arch/x86/kernel/cpu/perfctr-watchdog.c
10699 views
/*1* local apic based NMI watchdog for various CPUs.2*3* This file also handles reservation of performance counters for coordination4* with other users (like oprofile).5*6* Note that these events normally don't tick when the CPU idles. This means7* the frequency varies with CPU load.8*9* Original code for K7/P6 written by Keith Owens10*11*/1213#include <linux/percpu.h>14#include <linux/module.h>15#include <linux/kernel.h>16#include <linux/bitops.h>17#include <linux/smp.h>18#include <asm/nmi.h>19#include <linux/kprobes.h>2021#include <asm/apic.h>22#include <asm/perf_event.h>2324/*25* this number is calculated from Intel's MSR_P4_CRU_ESCR5 register and it's26* offset from MSR_P4_BSU_ESCR0.27*28* It will be the max for all platforms (for now)29*/30#define NMI_MAX_COUNTER_BITS 663132/*33* perfctr_nmi_owner tracks the ownership of the perfctr registers:34* evtsel_nmi_owner tracks the ownership of the event selection35* - different performance counters/ event selection may be reserved for36* different subsystems this reservation system just tries to coordinate37* things a little38*/39static DECLARE_BITMAP(perfctr_nmi_owner, NMI_MAX_COUNTER_BITS);40static DECLARE_BITMAP(evntsel_nmi_owner, NMI_MAX_COUNTER_BITS);4142/* converts an msr to an appropriate reservation bit */43static inline unsigned int nmi_perfctr_msr_to_bit(unsigned int msr)44{45/* returns the bit offset of the performance counter register */46switch (boot_cpu_data.x86_vendor) {47case X86_VENDOR_AMD:48if (msr >= MSR_F15H_PERF_CTR)49return (msr - MSR_F15H_PERF_CTR) >> 1;50return msr - MSR_K7_PERFCTR0;51case X86_VENDOR_INTEL:52if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))53return msr - MSR_ARCH_PERFMON_PERFCTR0;5455switch (boot_cpu_data.x86) {56case 6:57return msr - MSR_P6_PERFCTR0;58case 15:59return msr - MSR_P4_BPU_PERFCTR0;60}61}62return 0;63}6465/*66* converts an msr to an appropriate reservation bit67* returns the bit offset of the event selection register68*/69static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr)70{71/* returns the bit offset of the event selection register */72switch (boot_cpu_data.x86_vendor) {73case X86_VENDOR_AMD:74if (msr >= MSR_F15H_PERF_CTL)75return (msr - MSR_F15H_PERF_CTL) >> 1;76return msr - MSR_K7_EVNTSEL0;77case X86_VENDOR_INTEL:78if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))79return msr - MSR_ARCH_PERFMON_EVENTSEL0;8081switch (boot_cpu_data.x86) {82case 6:83return msr - MSR_P6_EVNTSEL0;84case 15:85return msr - MSR_P4_BSU_ESCR0;86}87}88return 0;8990}9192/* checks for a bit availability (hack for oprofile) */93int avail_to_resrv_perfctr_nmi_bit(unsigned int counter)94{95BUG_ON(counter > NMI_MAX_COUNTER_BITS);9697return !test_bit(counter, perfctr_nmi_owner);98}99EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi_bit);100101int reserve_perfctr_nmi(unsigned int msr)102{103unsigned int counter;104105counter = nmi_perfctr_msr_to_bit(msr);106/* register not managed by the allocator? */107if (counter > NMI_MAX_COUNTER_BITS)108return 1;109110if (!test_and_set_bit(counter, perfctr_nmi_owner))111return 1;112return 0;113}114EXPORT_SYMBOL(reserve_perfctr_nmi);115116void release_perfctr_nmi(unsigned int msr)117{118unsigned int counter;119120counter = nmi_perfctr_msr_to_bit(msr);121/* register not managed by the allocator? */122if (counter > NMI_MAX_COUNTER_BITS)123return;124125clear_bit(counter, perfctr_nmi_owner);126}127EXPORT_SYMBOL(release_perfctr_nmi);128129int reserve_evntsel_nmi(unsigned int msr)130{131unsigned int counter;132133counter = nmi_evntsel_msr_to_bit(msr);134/* register not managed by the allocator? */135if (counter > NMI_MAX_COUNTER_BITS)136return 1;137138if (!test_and_set_bit(counter, evntsel_nmi_owner))139return 1;140return 0;141}142EXPORT_SYMBOL(reserve_evntsel_nmi);143144void release_evntsel_nmi(unsigned int msr)145{146unsigned int counter;147148counter = nmi_evntsel_msr_to_bit(msr);149/* register not managed by the allocator? */150if (counter > NMI_MAX_COUNTER_BITS)151return;152153clear_bit(counter, evntsel_nmi_owner);154}155EXPORT_SYMBOL(release_evntsel_nmi);156157158