summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2009-07-08 10:21:41 +0200
committerIngo Molnar <mingo@elte.hu>2009-07-10 10:28:27 +0200
commit9c74fb50867e8fb5f3be3be06716492c0f79309e (patch)
tree52f5ca52ae0ac6c8430b79ba77f37f7e40a4ec96 /arch
parentperf_counter: Add P6 PMU support (diff)
downloadlinux-9c74fb50867e8fb5f3be3be06716492c0f79309e.tar.xz
linux-9c74fb50867e8fb5f3be3be06716492c0f79309e.zip
perf_counter: Fix up P6 PMU details
The P6 doesn't seem to support cache ref/hit/miss counts, so we extend the generic hardware event codes to have 0 and -1 mean the same thing as for the generic cache events. Furthermore, it turns out the 0 event does not count (that is, its reported that on PPro it actually does count something), therefore use a event configuration that's specified not to count to disable the counters. Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <new-submission> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kernel/cpu/perf_counter.c28
1 files changed, 23 insertions, 5 deletions
diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c
index 1910f39ff19a..c7cc6eac14ec 100644
--- a/arch/x86/kernel/cpu/perf_counter.c
+++ b/arch/x86/kernel/cpu/perf_counter.c
@@ -84,6 +84,14 @@ static u64 p6_pmu_event_map(int event)
return p6_perfmon_event_map[event];
}
+/*
+ * Counter setting that is specified not to count anything.
+ * We use this to effectively disable a counter.
+ *
+ * L2_RQSTS with 0 MESI unit mask.
+ */
+#define P6_NOP_COUNTER 0x0000002EULL
+
static u64 p6_pmu_raw_event(u64 event)
{
#define P6_EVNTSEL_EVENT_MASK 0x000000FFULL
@@ -704,6 +712,7 @@ static int __hw_perf_counter_init(struct perf_counter *counter)
{
struct perf_counter_attr *attr = &counter->attr;
struct hw_perf_counter *hwc = &counter->hw;
+ u64 config;
int err;
if (!x86_pmu_initialized())
@@ -756,10 +765,19 @@ static int __hw_perf_counter_init(struct perf_counter *counter)
if (attr->config >= x86_pmu.max_events)
return -EINVAL;
+
/*
* The generic map:
*/
- hwc->config |= x86_pmu.event_map(attr->config);
+ config = x86_pmu.event_map(attr->config);
+
+ if (config == 0)
+ return -ENOENT;
+
+ if (config == -1LL)
+ return -EINVAL;
+
+ hwc->config |= config;
return 0;
}
@@ -767,7 +785,7 @@ static int __hw_perf_counter_init(struct perf_counter *counter)
static void p6_pmu_disable_all(void)
{
struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
- unsigned long val;
+ u64 val;
if (!cpuc->enabled)
return;
@@ -917,10 +935,10 @@ static inline void
p6_pmu_disable_counter(struct hw_perf_counter *hwc, int idx)
{
struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
- unsigned long val = ARCH_PERFMON_EVENTSEL0_ENABLE;
+ u64 val = P6_NOP_COUNTER;
- if (!cpuc->enabled)
- val = 0;
+ if (cpuc->enabled)
+ val |= ARCH_PERFMON_EVENTSEL0_ENABLE;
(void)checking_wrmsrl(hwc->config_base + idx, val);
}