Path: blob/master/arch/x86/kernel/cpu/perfctr-watchdog.c
26493 views
// SPDX-License-Identifier: GPL-2.01/*2* local apic based NMI watchdog for various CPUs.3*4* This file also handles reservation of performance counters for coordination5* with other users.6*7* Note that these events normally don't tick when the CPU idles. This means8* the frequency varies with CPU load.9*10* Original code for K7/P6 written by Keith Owens11*12*/1314#include <linux/percpu.h>15#include <linux/export.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>2122#include <asm/apic.h>23#include <asm/perf_event.h>2425/*26* this number is calculated from Intel's MSR_P4_CRU_ESCR5 register and it's27* 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 663233/*34* perfctr_nmi_owner tracks the ownership of the perfctr registers:35* evtsel_nmi_owner tracks the ownership of the event selection36* - different performance counters/ event selection may be reserved for37* different subsystems this reservation system just tries to coordinate38* things a little39*/40static DECLARE_BITMAP(perfctr_nmi_owner, NMI_MAX_COUNTER_BITS);41static DECLARE_BITMAP(evntsel_nmi_owner, NMI_MAX_COUNTER_BITS);4243/* 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 */47switch (boot_cpu_data.x86_vendor) {48case X86_VENDOR_HYGON:49case X86_VENDOR_AMD:50if (msr >= MSR_F15H_PERF_CTR)51return (msr - MSR_F15H_PERF_CTR) >> 1;52return msr - MSR_K7_PERFCTR0;53case X86_VENDOR_INTEL:54if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))55return msr - MSR_ARCH_PERFMON_PERFCTR0;5657switch (boot_cpu_data.x86) {58case 6:59return msr - MSR_P6_PERFCTR0;60case 11:61return msr - MSR_KNC_PERFCTR0;62case 15:63return msr - MSR_P4_BPU_PERFCTR0;64}65break;66case X86_VENDOR_ZHAOXIN:67case X86_VENDOR_CENTAUR:68return msr - MSR_ARCH_PERFMON_PERFCTR0;69}70return 0;71}7273/*74* converts an msr to an appropriate reservation bit75* returns the bit offset of the event selection register76*/77static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr)78{79/* returns the bit offset of the event selection register */80switch (boot_cpu_data.x86_vendor) {81case X86_VENDOR_HYGON:82case X86_VENDOR_AMD:83if (msr >= MSR_F15H_PERF_CTL)84return (msr - MSR_F15H_PERF_CTL) >> 1;85return msr - MSR_K7_EVNTSEL0;86case X86_VENDOR_INTEL:87if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))88return msr - MSR_ARCH_PERFMON_EVENTSEL0;8990switch (boot_cpu_data.x86) {91case 6:92return msr - MSR_P6_EVNTSEL0;93case 11:94return msr - MSR_KNC_EVNTSEL0;95case 15:96return msr - MSR_P4_BSU_ESCR0;97}98break;99case X86_VENDOR_ZHAOXIN:100case X86_VENDOR_CENTAUR:101return msr - MSR_ARCH_PERFMON_EVENTSEL0;102}103return 0;104105}106107int reserve_perfctr_nmi(unsigned int msr)108{109unsigned int counter;110111counter = nmi_perfctr_msr_to_bit(msr);112/* register not managed by the allocator? */113if (counter > NMI_MAX_COUNTER_BITS)114return 1;115116if (!test_and_set_bit(counter, perfctr_nmi_owner))117return 1;118return 0;119}120EXPORT_SYMBOL(reserve_perfctr_nmi);121122void release_perfctr_nmi(unsigned int msr)123{124unsigned int counter;125126counter = nmi_perfctr_msr_to_bit(msr);127/* register not managed by the allocator? */128if (counter > NMI_MAX_COUNTER_BITS)129return;130131clear_bit(counter, perfctr_nmi_owner);132}133EXPORT_SYMBOL(release_perfctr_nmi);134135int reserve_evntsel_nmi(unsigned int msr)136{137unsigned int counter;138139counter = nmi_evntsel_msr_to_bit(msr);140/* register not managed by the allocator? */141if (counter > NMI_MAX_COUNTER_BITS)142return 1;143144if (!test_and_set_bit(counter, evntsel_nmi_owner))145return 1;146return 0;147}148EXPORT_SYMBOL(reserve_evntsel_nmi);149150void release_evntsel_nmi(unsigned int msr)151{152unsigned int counter;153154counter = nmi_evntsel_msr_to_bit(msr);155/* register not managed by the allocator? */156if (counter > NMI_MAX_COUNTER_BITS)157return;158159clear_bit(counter, evntsel_nmi_owner);160}161EXPORT_SYMBOL(release_evntsel_nmi);162163164