Commit 86615559 authored by John Levon's avatar John Levon Committed by Tony Luck

[IA64] support for IA64 hardware performance counters via the perfmon interface

 
   This patch provides support for IA64 hardware performance counters via
   the perfmon interface. Please consider applying.
Signed-off-by: default avatarJohn Levon <levon@movementarian.org>
Signed-off-by: default avatarTony Luck <tony.luck@intel.com>
parent 65fd90f1
......@@ -16,6 +16,10 @@ config OPROFILE
whole system, include the kernel, kernel modules, libraries,
and applications.
Due to firmware bugs, you may need to use the "nohalt" boot
option if you're using OProfile with the hardware performance
counters.
If unsure, say N.
endmenu
......
......@@ -7,3 +7,4 @@ DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \
timer_int.o )
oprofile-y := $(DRIVER_OBJS) init.o
oprofile-$(CONFIG_PERFMON) += perfmon.o
......@@ -12,14 +12,21 @@
#include <linux/init.h>
#include <linux/errno.h>
extern void timer_init(struct oprofile_operations ** ops);
extern int perfmon_init(struct oprofile_operations ** ops);
extern void perfmon_exit(void);
int __init oprofile_arch_init(struct oprofile_operations ** ops)
{
#ifdef CONFIG_PERFMON
return perfmon_init(ops);
#endif
return -ENODEV;
}
void oprofile_arch_exit(void)
{
#ifdef CONFIG_PERFMON
perfmon_exit();
#endif
}
/**
* @file perfmon.c
*
* @remark Copyright 2003 OProfile authors
* @remark Read the file COPYING
*
* @author John Levon <levon@movementarian.org>
*/
#include <linux/kernel.h>
#include <linux/config.h>
#include <linux/oprofile.h>
#include <linux/sched.h>
#include <asm/perfmon.h>
#include <asm/ptrace.h>
#include <asm/errno.h>
static int allow_ints;
static int
perfmon_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg,
struct pt_regs *regs, unsigned long stamp)
{
int cpu = smp_processor_id();
unsigned long eip = instruction_pointer(regs);
int event = arg->pmd_eventid;
arg->ovfl_ctrl.bits.reset_ovfl_pmds = 1;
/* the owner of the oprofile event buffer may have exited
* without perfmon being shutdown (e.g. SIGSEGV)
*/
if (allow_ints)
oprofile_add_sample(eip, !user_mode(regs), event, cpu);
return 0;
}
static int perfmon_start(void)
{
allow_ints = 1;
return 0;
}
static void perfmon_stop(void)
{
allow_ints = 0;
}
#define OPROFILE_FMT_UUID { \
0x77, 0x7a, 0x6e, 0x61, 0x20, 0x65, 0x73, 0x69, 0x74, 0x6e, 0x72, 0x20, 0x61, 0x65, 0x0a, 0x6c }
static pfm_buffer_fmt_t oprofile_fmt = {
.fmt_name = "oprofile_format",
.fmt_uuid = OPROFILE_FMT_UUID,
.fmt_handler = perfmon_handler,
};
static char * get_cpu_type(void)
{
__u8 family = local_cpu_data->family;
switch (family) {
case 0x07:
return "ia64/itanium";
case 0x1f:
return "ia64/itanium2";
default:
return "ia64/ia64";
}
}
/* all the ops are handled via userspace for IA64 perfmon */
static struct oprofile_operations perfmon_ops = {
.start = perfmon_start,
.stop = perfmon_stop,
};
static int using_perfmon;
int perfmon_init(struct oprofile_operations ** ops)
{
int ret = pfm_register_buffer_fmt(&oprofile_fmt);
if (ret)
return -ENODEV;
perfmon_ops.cpu_type = get_cpu_type();
*ops = &perfmon_ops;
using_perfmon = 1;
printk(KERN_INFO "oprofile: using perfmon.\n");
return 0;
}
void perfmon_exit(void)
{
if (!using_perfmon)
return;
pfm_unregister_buffer_fmt(oprofile_fmt.fmt_uuid);
}
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