2008-06-25 04:52:03 +08:00
|
|
|
/*
|
|
|
|
* local apic based NMI watchdog for various CPUs.
|
|
|
|
*
|
|
|
|
* This file also handles reservation of performance counters for coordination
|
|
|
|
* with other users (like oprofile).
|
|
|
|
*
|
|
|
|
* Note that these events normally don't tick when the CPU idles. This means
|
|
|
|
* the frequency varies with CPU load.
|
|
|
|
*
|
|
|
|
* Original code for K7/P6 written by Keith Owens
|
|
|
|
*
|
|
|
|
*/
|
2007-05-03 01:27:20 +08:00
|
|
|
|
|
|
|
#include <linux/percpu.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/bitops.h>
|
|
|
|
#include <linux/smp.h>
|
x86, nmi_watchdog: Remove ARCH_HAS_NMI_WATCHDOG and rely on CONFIG_HARDLOCKUP_DETECTOR
The x86 arch has shifted its use of the nmi_watchdog from a
local implementation to the global one provide by
kernel/watchdog.c. This shift has caused a whole bunch of
compile problems under different config options. I attempt to
simplify things with the patch below.
In order to simplify things, I had to come to terms with the
meaning of two terms ARCH_HAS_NMI_WATCHDOG and
CONFIG_HARDLOCKUP_DETECTOR. Basically they mean the same thing,
the former on a local level and the latter on a global level.
With the old x86 nmi watchdog gone, there is no need to rely on
defining the ARCH_HAS_NMI_WATCHDOG variable because it doesn't
make sense any more. x86 will now use the global
implementation.
The changes below do a few things. First it changes the few
places that relied on ARCH_HAS_NMI_WATCHDOG to use
CONFIG_X86_LOCAL_APIC (the former was an alias for the latter
anyway, so nothing unusual here). Those pieces of code were
relying more on local apic functionality the nmi watchdog
functionality, so the change should make sense.
Second, I removed the x86 implementation of
touch_nmi_watchdog(). It isn't need now, instead x86 will rely
on kernel/watchdog.c's implementation.
Third, I removed the #define ARCH_HAS_NMI_WATCHDOG itself from
x86. And tweaked the include/linux/nmi.h file to tell users to
look for an externally defined touch_nmi_watchdog in the case of
ARCH_HAS_NMI_WATCHDOG _or_ CONFIG_HARDLOCKUP_DETECTOR. This
changes removes some of the ugliness in that file.
Finally, I added a Kconfig dependency for
CONFIG_HARDLOCKUP_DETECTOR that said you can't have
ARCH_HAS_NMI_WATCHDOG _and_ CONFIG_HARDLOCKUP_DETECTOR. You can
only have one nmi_watchdog.
Tested with
ARCH=i386: allnoconfig, defconfig, allyesconfig, (various broken
configs) ARCH=x86_64: allnoconfig, defconfig, allyesconfig,
(various broken configs)
Hopefully, after this patch I won't get any more compile broken
emails. :-)
v3:
changed a couple of 'linux/nmi.h' -> 'asm/nmi.h' to pick-up correct function
prototypes when CONFIG_HARDLOCKUP_DETECTOR is not set.
Signed-off-by: Don Zickus <dzickus@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: fweisbec@gmail.com
LKML-Reference: <1293044403-14117-1-git-send-email-dzickus@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-12-23 03:00:03 +08:00
|
|
|
#include <asm/nmi.h>
|
2008-07-29 18:36:02 +08:00
|
|
|
#include <linux/kprobes.h>
|
|
|
|
|
2007-05-03 01:27:20 +08:00
|
|
|
#include <asm/apic.h>
|
perf: Do the big rename: Performance Counters -> Performance Events
Bye-bye Performance Counters, welcome Performance Events!
In the past few months the perfcounters subsystem has grown out its
initial role of counting hardware events, and has become (and is
becoming) a much broader generic event enumeration, reporting, logging,
monitoring, analysis facility.
Naming its core object 'perf_counter' and naming the subsystem
'perfcounters' has become more and more of a misnomer. With pending
code like hw-breakpoints support the 'counter' name is less and
less appropriate.
All in one, we've decided to rename the subsystem to 'performance
events' and to propagate this rename through all fields, variables
and API names. (in an ABI compatible fashion)
The word 'event' is also a bit shorter than 'counter' - which makes
it slightly more convenient to write/handle as well.
Thanks goes to Stephane Eranian who first observed this misnomer and
suggested a rename.
User-space tooling and ABI compatibility is not affected - this patch
should be function-invariant. (Also, defconfigs were not touched to
keep the size down.)
This patch has been generated via the following script:
FILES=$(find * -type f | grep -vE 'oprofile|[^K]config')
sed -i \
-e 's/PERF_EVENT_/PERF_RECORD_/g' \
-e 's/PERF_COUNTER/PERF_EVENT/g' \
-e 's/perf_counter/perf_event/g' \
-e 's/nb_counters/nb_events/g' \
-e 's/swcounter/swevent/g' \
-e 's/tpcounter_event/tp_event/g' \
$FILES
for N in $(find . -name perf_counter.[ch]); do
M=$(echo $N | sed 's/perf_counter/perf_event/g')
mv $N $M
done
FILES=$(find . -name perf_event.*)
sed -i \
-e 's/COUNTER_MASK/REG_MASK/g' \
-e 's/COUNTER/EVENT/g' \
-e 's/\<event\>/event_id/g' \
-e 's/counter/event/g' \
-e 's/Counter/Event/g' \
$FILES
... to keep it as correct as possible. This script can also be
used by anyone who has pending perfcounters patches - it converts
a Linux kernel tree over to the new naming. We tried to time this
change to the point in time where the amount of pending patches
is the smallest: the end of the merge window.
Namespace clashes were fixed up in a preparatory patch - and some
stylistic fallout will be fixed up in a subsequent patch.
( NOTE: 'counters' are still the proper terminology when we deal
with hardware registers - and these sed scripts are a bit
over-eager in renaming them. I've undone some of that, but
in case there's something left where 'counter' would be
better than 'event' we can undo that on an individual basis
instead of touching an otherwise nicely automated patch. )
Suggested-by: Stephane Eranian <eranian@google.com>
Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Acked-by: Paul Mackerras <paulus@samba.org>
Reviewed-by: Arjan van de Ven <arjan@linux.intel.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: David Howells <dhowells@redhat.com>
Cc: Kyle McMartin <kyle@mcmartin.ca>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: <linux-arch@vger.kernel.org>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-09-21 18:02:48 +08:00
|
|
|
#include <asm/perf_event.h>
|
2007-05-03 01:27:20 +08:00
|
|
|
|
2008-06-25 04:52:03 +08:00
|
|
|
/*
|
|
|
|
* this number is calculated from Intel's MSR_P4_CRU_ESCR5 register and it's
|
|
|
|
* offset from MSR_P4_BSU_ESCR0.
|
|
|
|
*
|
|
|
|
* It will be the max for all platforms (for now)
|
2007-05-03 01:27:20 +08:00
|
|
|
*/
|
|
|
|
#define NMI_MAX_COUNTER_BITS 66
|
|
|
|
|
2008-06-25 04:52:03 +08:00
|
|
|
/*
|
|
|
|
* perfctr_nmi_owner tracks the ownership of the perfctr registers:
|
2007-05-03 01:27:20 +08:00
|
|
|
* evtsel_nmi_owner tracks the ownership of the event selection
|
|
|
|
* - different performance counters/ event selection may be reserved for
|
|
|
|
* different subsystems this reservation system just tries to coordinate
|
|
|
|
* things a little
|
|
|
|
*/
|
|
|
|
static DECLARE_BITMAP(perfctr_nmi_owner, NMI_MAX_COUNTER_BITS);
|
|
|
|
static DECLARE_BITMAP(evntsel_nmi_owner, NMI_MAX_COUNTER_BITS);
|
|
|
|
|
|
|
|
/* converts an msr to an appropriate reservation bit */
|
|
|
|
static inline unsigned int nmi_perfctr_msr_to_bit(unsigned int msr)
|
|
|
|
{
|
2007-07-04 07:38:13 +08:00
|
|
|
/* returns the bit offset of the performance counter register */
|
|
|
|
switch (boot_cpu_data.x86_vendor) {
|
|
|
|
case X86_VENDOR_AMD:
|
2011-02-03 00:40:58 +08:00
|
|
|
if (msr >= MSR_F15H_PERF_CTR)
|
|
|
|
return (msr - MSR_F15H_PERF_CTR) >> 1;
|
2009-07-04 07:35:45 +08:00
|
|
|
return msr - MSR_K7_PERFCTR0;
|
2007-07-04 07:38:13 +08:00
|
|
|
case X86_VENDOR_INTEL:
|
|
|
|
if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
|
2009-07-04 07:35:45 +08:00
|
|
|
return msr - MSR_ARCH_PERFMON_PERFCTR0;
|
2007-07-04 07:38:13 +08:00
|
|
|
|
|
|
|
switch (boot_cpu_data.x86) {
|
|
|
|
case 6:
|
2009-07-04 07:35:45 +08:00
|
|
|
return msr - MSR_P6_PERFCTR0;
|
2012-09-27 02:12:52 +08:00
|
|
|
case 11:
|
|
|
|
return msr - MSR_KNC_PERFCTR0;
|
2007-07-04 07:38:13 +08:00
|
|
|
case 15:
|
2009-07-04 07:35:45 +08:00
|
|
|
return msr - MSR_P4_BPU_PERFCTR0;
|
2007-07-04 07:38:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
2007-05-03 01:27:20 +08:00
|
|
|
}
|
|
|
|
|
2008-06-25 04:52:03 +08:00
|
|
|
/*
|
|
|
|
* converts an msr to an appropriate reservation bit
|
|
|
|
* returns the bit offset of the event selection register
|
|
|
|
*/
|
2007-05-03 01:27:20 +08:00
|
|
|
static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr)
|
|
|
|
{
|
2007-07-04 07:38:13 +08:00
|
|
|
/* returns the bit offset of the event selection register */
|
|
|
|
switch (boot_cpu_data.x86_vendor) {
|
|
|
|
case X86_VENDOR_AMD:
|
2011-02-03 00:40:58 +08:00
|
|
|
if (msr >= MSR_F15H_PERF_CTL)
|
|
|
|
return (msr - MSR_F15H_PERF_CTL) >> 1;
|
2009-07-04 07:35:45 +08:00
|
|
|
return msr - MSR_K7_EVNTSEL0;
|
2007-07-04 07:38:13 +08:00
|
|
|
case X86_VENDOR_INTEL:
|
|
|
|
if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
|
2009-07-04 07:35:45 +08:00
|
|
|
return msr - MSR_ARCH_PERFMON_EVENTSEL0;
|
2007-07-04 07:38:13 +08:00
|
|
|
|
|
|
|
switch (boot_cpu_data.x86) {
|
|
|
|
case 6:
|
2009-07-04 07:35:45 +08:00
|
|
|
return msr - MSR_P6_EVNTSEL0;
|
2012-09-27 02:12:52 +08:00
|
|
|
case 11:
|
|
|
|
return msr - MSR_KNC_EVNTSEL0;
|
2007-07-04 07:38:13 +08:00
|
|
|
case 15:
|
2009-07-04 07:35:45 +08:00
|
|
|
return msr - MSR_P4_BSU_ESCR0;
|
2007-07-04 07:38:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
2007-05-03 01:27:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* checks for a bit availability (hack for oprofile) */
|
|
|
|
int avail_to_resrv_perfctr_nmi_bit(unsigned int counter)
|
|
|
|
{
|
|
|
|
BUG_ON(counter > NMI_MAX_COUNTER_BITS);
|
|
|
|
|
2009-07-04 07:35:45 +08:00
|
|
|
return !test_bit(counter, perfctr_nmi_owner);
|
2007-05-03 01:27:20 +08:00
|
|
|
}
|
2008-06-25 04:52:03 +08:00
|
|
|
EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi_bit);
|
2007-05-03 01:27:20 +08:00
|
|
|
|
|
|
|
int reserve_perfctr_nmi(unsigned int msr)
|
|
|
|
{
|
|
|
|
unsigned int counter;
|
|
|
|
|
|
|
|
counter = nmi_perfctr_msr_to_bit(msr);
|
2007-10-20 02:35:04 +08:00
|
|
|
/* register not managed by the allocator? */
|
|
|
|
if (counter > NMI_MAX_COUNTER_BITS)
|
|
|
|
return 1;
|
2007-05-03 01:27:20 +08:00
|
|
|
|
|
|
|
if (!test_and_set_bit(counter, perfctr_nmi_owner))
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
2008-06-25 04:52:03 +08:00
|
|
|
EXPORT_SYMBOL(reserve_perfctr_nmi);
|
2007-05-03 01:27:20 +08:00
|
|
|
|
|
|
|
void release_perfctr_nmi(unsigned int msr)
|
|
|
|
{
|
|
|
|
unsigned int counter;
|
|
|
|
|
|
|
|
counter = nmi_perfctr_msr_to_bit(msr);
|
2007-10-20 02:35:04 +08:00
|
|
|
/* register not managed by the allocator? */
|
|
|
|
if (counter > NMI_MAX_COUNTER_BITS)
|
|
|
|
return;
|
2007-05-03 01:27:20 +08:00
|
|
|
|
|
|
|
clear_bit(counter, perfctr_nmi_owner);
|
|
|
|
}
|
2008-06-25 04:52:03 +08:00
|
|
|
EXPORT_SYMBOL(release_perfctr_nmi);
|
2007-05-03 01:27:20 +08:00
|
|
|
|
|
|
|
int reserve_evntsel_nmi(unsigned int msr)
|
|
|
|
{
|
|
|
|
unsigned int counter;
|
|
|
|
|
|
|
|
counter = nmi_evntsel_msr_to_bit(msr);
|
2007-10-20 02:35:04 +08:00
|
|
|
/* register not managed by the allocator? */
|
|
|
|
if (counter > NMI_MAX_COUNTER_BITS)
|
|
|
|
return 1;
|
2007-05-03 01:27:20 +08:00
|
|
|
|
|
|
|
if (!test_and_set_bit(counter, evntsel_nmi_owner))
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
2008-06-25 04:52:03 +08:00
|
|
|
EXPORT_SYMBOL(reserve_evntsel_nmi);
|
2007-05-03 01:27:20 +08:00
|
|
|
|
|
|
|
void release_evntsel_nmi(unsigned int msr)
|
|
|
|
{
|
|
|
|
unsigned int counter;
|
|
|
|
|
|
|
|
counter = nmi_evntsel_msr_to_bit(msr);
|
2007-10-20 02:35:04 +08:00
|
|
|
/* register not managed by the allocator? */
|
|
|
|
if (counter > NMI_MAX_COUNTER_BITS)
|
|
|
|
return;
|
2007-05-03 01:27:20 +08:00
|
|
|
|
|
|
|
clear_bit(counter, evntsel_nmi_owner);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(release_evntsel_nmi);
|