Skip to content

Commit

Permalink
perf/x86: Enable overflow on Intel KNC with a custom knc_pmu_handle_i…
Browse files Browse the repository at this point in the history
…rq()

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: Vince 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: Ingo Molnar <mingo@kernel.org>
  • Loading branch information
deater authored and Ingo Molnar committed Oct 24, 2012
1 parent 7d01196 commit e4074b3
Showing 1 changed file with 77 additions and 1 deletion.
78 changes: 77 additions & 1 deletion arch/x86/kernel/cpu/perf_event_knc.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include <linux/perf_event.h>
#include <linux/types.h>

#include <asm/hardirq.h>

#include "perf_event.h"

static const u64 knc_perfmon_event_map[] =
Expand Down Expand Up @@ -193,6 +195,80 @@ static void knc_pmu_enable_event(struct perf_event *event)
(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(umask, "config:8-15" );
PMU_FORMAT_ATTR(edge, "config:18" );
Expand All @@ -210,7 +286,7 @@ static struct attribute *intel_knc_formats_attr[] = {

static __initconst struct x86_pmu knc_pmu = {
.name = "knc",
.handle_irq = x86_pmu_handle_irq,
.handle_irq = knc_pmu_handle_irq,
.disable_all = knc_pmu_disable_all,
.enable_all = knc_pmu_enable_all,
.enable = knc_pmu_enable_event,
Expand Down

0 comments on commit e4074b3

Please sign in to comment.