Commit e4074b30 authored by Vince Weaver's avatar Vince Weaver Committed by Ingo Molnar

perf/x86: Enable overflow on Intel KNC with a custom knc_pmu_handle_irq()

Although based on the Intel P6 design, the interrupt mechnanism
for KNC more closely resembles the Intel architectural
perfmon one.

We can't just re-use that code though, because KNC has different
MSR numbers for the status and ack registers.

In this case we just cut-and paste from perf_event_intel.c
with some minor changes, as it looks like it would not be
worth the trouble to change that code to be MSR-configurable.
Signed-off-by: default avatarVince Weaver <vincent.weaver@maine.edu>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: eranian@gmail.com
Cc: Meadows Lawrence F <lawrence.f.meadows@intel.com>
Link: http://lkml.kernel.org/r/alpine.DEB.2.02.1210171304410.23243@vincent-weaver-1.um.maine.edu
[ Small stylistic edits. ]
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 7d011962
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
#include <linux/perf_event.h> #include <linux/perf_event.h>
#include <linux/types.h> #include <linux/types.h>
#include <asm/hardirq.h>
#include "perf_event.h" #include "perf_event.h"
static const u64 knc_perfmon_event_map[] = static const u64 knc_perfmon_event_map[] =
...@@ -193,6 +195,80 @@ static void knc_pmu_enable_event(struct perf_event *event) ...@@ -193,6 +195,80 @@ static void knc_pmu_enable_event(struct perf_event *event)
(void)wrmsrl_safe(hwc->config_base + hwc->idx, val); (void)wrmsrl_safe(hwc->config_base + hwc->idx, val);
} }
static inline u64 knc_pmu_get_status(void)
{
u64 status;
rdmsrl(MSR_KNC_IA32_PERF_GLOBAL_STATUS, status);
return status;
}
static inline void knc_pmu_ack_status(u64 ack)
{
wrmsrl(MSR_KNC_IA32_PERF_GLOBAL_OVF_CONTROL, ack);
}
static int knc_pmu_handle_irq(struct pt_regs *regs)
{
struct perf_sample_data data;
struct cpu_hw_events *cpuc;
int handled = 0;
int bit, loops;
u64 status;
cpuc = &__get_cpu_var(cpu_hw_events);
knc_pmu_disable_all();
status = knc_pmu_get_status();
if (!status) {
knc_pmu_enable_all(0);
return handled;
}
loops = 0;
again:
knc_pmu_ack_status(status);
if (++loops > 100) {
WARN_ONCE(1, "perf: irq loop stuck!\n");
perf_event_print_debug();
goto done;
}
inc_irq_stat(apic_perf_irqs);
for_each_set_bit(bit, (unsigned long *)&status, X86_PMC_IDX_MAX) {
struct perf_event *event = cpuc->events[bit];
handled++;
if (!test_bit(bit, cpuc->active_mask))
continue;
if (!intel_pmu_save_and_restart(event))
continue;
perf_sample_data_init(&data, 0, event->hw.last_period);
if (perf_event_overflow(event, &data, regs))
x86_pmu_stop(event, 0);
}
/*
* Repeat if there is more work to be done:
*/
status = knc_pmu_get_status();
if (status)
goto again;
done:
knc_pmu_enable_all(0);
return handled;
}
PMU_FORMAT_ATTR(event, "config:0-7" ); PMU_FORMAT_ATTR(event, "config:0-7" );
PMU_FORMAT_ATTR(umask, "config:8-15" ); PMU_FORMAT_ATTR(umask, "config:8-15" );
PMU_FORMAT_ATTR(edge, "config:18" ); PMU_FORMAT_ATTR(edge, "config:18" );
...@@ -210,7 +286,7 @@ static struct attribute *intel_knc_formats_attr[] = { ...@@ -210,7 +286,7 @@ static struct attribute *intel_knc_formats_attr[] = {
static __initconst struct x86_pmu knc_pmu = { static __initconst struct x86_pmu knc_pmu = {
.name = "knc", .name = "knc",
.handle_irq = x86_pmu_handle_irq, .handle_irq = knc_pmu_handle_irq,
.disable_all = knc_pmu_disable_all, .disable_all = knc_pmu_disable_all,
.enable_all = knc_pmu_enable_all, .enable_all = knc_pmu_enable_all,
.enable = knc_pmu_enable_event, .enable = knc_pmu_enable_event,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment