--- linux-2.6.base/drivers/oprofile/timer_int.c	2006-10-17 05:37:59.000000000 -0700
+++ linux-2.6/drivers/oprofile/timer_int.c	2007-01-05 06:23:06.000000000 -0800
@@ -43,4 +43,5 @@ void __init oprofile_timer_init(struct o
 	ops->start = timer_start;
 	ops->stop = timer_stop;
 	ops->cpu_type = "timer";
+	ops->implementation = "timer";
 }
--- linux-2.6.base/drivers/oprofile/oprofile_files.c	2006-10-17 05:37:59.000000000 -0700
+++ linux-2.6/drivers/oprofile/oprofile_files.c	2007-01-05 06:22:33.000000000 -0800
@@ -117,7 +117,17 @@ static ssize_t dump_write(struct file * 
 static struct file_operations dump_fops = {
 	.write		= dump_write,
 };
- 
+
+static ssize_t implementation(struct file * file, char __user * buf, size_t count, loff_t * offset)
+{
+	return oprofilefs_str_to_user(oprofile_ops.implementation, buf, count, offset);
+}
+
+
+static struct file_operations implementation_fops = {
+	.read		= implementation,
+};
+
 void oprofile_create_files(struct super_block * sb, struct dentry * root)
 {
 	oprofilefs_create_file(sb, root, "enable", &enable_fops);
@@ -127,6 +137,7 @@ void oprofile_create_files(struct super_
 	oprofilefs_create_ulong(sb, root, "buffer_watershed", &fs_buffer_watershed);
 	oprofilefs_create_ulong(sb, root, "cpu_buffer_size", &fs_cpu_buffer_size);
 	oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops); 
+	oprofilefs_create_file(sb, root, "implementation", &implementation_fops);
 	oprofilefs_create_file(sb, root, "backtrace_depth", &depth_fops);
 	oprofilefs_create_file(sb, root, "pointer_size", &pointer_size_fops);
 	oprofile_create_stats_files(sb, root);
--- linux-2.6.base/arch/x86_64/oprofile/Makefile	2006-10-17 05:37:33.000000000 -0700
+++ linux-2.6/arch/x86_64/oprofile/Makefile	2007-01-05 06:23:43.000000000 -0800
@@ -15,5 +15,6 @@ OPROFILE-y := init.o backtrace.o
 OPROFILE-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o op_model_p4.o \
 				     op_model_ppro.o
 OPROFILE-$(CONFIG_X86_IO_APIC)    += nmi_timer_int.o 
+OPROFILE-$(CONFIG_PERFMON)	  += perfmon.o
 
 oprofile-y = $(DRIVER_OBJS) $(addprefix ../../i386/oprofile/, $(OPROFILE-y))
--- linux-2.6.base/arch/i386/oprofile/nmi_int.c	2006-10-17 05:37:30.000000000 -0700
+++ linux-2.6/arch/i386/oprofile/nmi_int.c	2007-01-05 06:24:15.000000000 -0800
@@ -448,6 +448,7 @@ int __init op_nmi_init(struct oprofile_o
 	ops->start = nmi_start;
 	ops->stop = nmi_stop;
 	ops->cpu_type = cpu_type;
+	ops->implementation = "oprofile";
 	printk(KERN_INFO "oprofile: using NMI interrupt.\n");
 	return 0;
 }
--- linux-2.6.base/arch/i386/oprofile/Makefile	2006-10-17 05:37:30.000000000 -0700
+++ linux-2.6/arch/i386/oprofile/Makefile	2007-01-05 06:24:35.000000000 -0800
@@ -10,3 +10,4 @@ oprofile-y				:= $(DRIVER_OBJS) init.o b
 oprofile-$(CONFIG_X86_LOCAL_APIC) 	+= nmi_int.o op_model_athlon.o \
 					   op_model_ppro.o op_model_p4.o
 oprofile-$(CONFIG_X86_IO_APIC)		+= nmi_timer_int.o
+oprofile-$(CONFIG_PERFMON)		+= perfmon.o
--- linux-2.6.base/arch/i386/oprofile/init.c	2006-10-17 05:37:30.000000000 -0700
+++ linux-2.6/arch/i386/oprofile/init.c	2007-01-05 06:26:16.000000000 -0800
@@ -15,9 +15,11 @@
  * with the NMI mode driver.
  */
  
+extern int op_perfmon_init(struct oprofile_operations * ops);
 extern int op_nmi_init(struct oprofile_operations * ops);
 extern int op_nmi_timer_init(struct oprofile_operations * ops);
 extern void op_nmi_exit(void);
+extern void op_perfmon_exit(void);
 extern void x86_backtrace(struct pt_regs * const regs, unsigned int depth);
 
 
@@ -27,8 +29,12 @@ int __init oprofile_arch_init(struct opr
 
 	ret = -ENODEV;
 
+#ifdef CONFIG_PERFMON
+	ret = op_perfmon_init(ops);
+#endif
 #ifdef CONFIG_X86_LOCAL_APIC
-	ret = op_nmi_init(ops);
+	if (ret < 0)
+		ret = op_nmi_init(ops);
 #endif
 #ifdef CONFIG_X86_IO_APIC
 	if (ret < 0)
@@ -42,6 +48,9 @@ int __init oprofile_arch_init(struct opr
 
 void oprofile_arch_exit(void)
 {
+#ifdef CONFIG_PERFMON
+	op_perfmon_exit();
+#endif
 #ifdef CONFIG_X86_LOCAL_APIC
 	op_nmi_exit();
 #endif
--- linux-2.6.base/arch/i386/oprofile/perfmon.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6/arch/i386/oprofile/perfmon.c	2007-01-09 07:34:40.000000000 -0800
@@ -0,0 +1,161 @@
+/**
+ * @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/module.h>
+#include <linux/oprofile.h>
+#include <linux/perfmon.h>
+
+static int allow_ints;
+
+static int
+perfmon_handler(void *buf, struct pfm_ovfl_arg *arg,
+                unsigned long ip, u64 stamp, void *data)
+{
+	struct pt_regs * const regs = data;
+	int event = arg->pmd_eventid;
+
+	PFM_DBG_ovfl("oprofile overflow ip=%lx, event=%d",
+		     instruction_pointer(regs), event);
+
+	arg->ovfl_ctrl = PFM_OVFL_CTRL_RESET;
+
+	/* the owner of the oprofile event buffer may have exited
+	 * without perfmon being shutdown (e.g. SIGSEGV)
+	 */
+	if (allow_ints)
+		oprofile_add_sample(regs, event);
+	return 0;
+}
+
+
+static int perfmon_start(void)
+{
+	allow_ints = 1;
+	return 0;
+}
+
+
+static void perfmon_stop(void)
+{
+	allow_ints = 0;
+}
+
+static struct pfm_smpl_fmt oprofile_fmt = {
+ 	.fmt_name = "OProfile",
+ 	.fmt_handler = perfmon_handler,
+	.fmt_flags = PFM_FMT_BUILTIN_FLAG,
+	.owner = THIS_MODULE
+};
+
+/* all the ops are handled via userspace for i386 oprofile using perfmon */
+
+static int using_perfmon;
+
+static int __init ppro_init(char ** cpu_type)
+{
+	__u8 cpu_model = boot_cpu_data.x86_model;
+
+	if (cpu_model == 14)
+		*cpu_type = "i386/core";
+	else if (cpu_model == 15)
+		*cpu_type = "i386/core_2";
+	else if (cpu_model > 0xd)
+		return 0;
+	else if (cpu_model == 9) {
+		*cpu_type = "i386/p6_mobile";
+	} else if (cpu_model > 5) {
+		*cpu_type = "i386/piii";
+	} else if (cpu_model > 2) {
+		*cpu_type = "i386/pii";
+	} else {
+		*cpu_type = "i386/ppro";
+	}
+	return 1;
+}
+
+static int __init p4_init(char ** cpu_type)
+{
+#ifndef CONFIG_SMP
+	*cpu_type = "i386/p4";
+	return 1;
+#else
+	switch (smp_num_siblings) {
+		case 1:
+			*cpu_type = "i386/p4";
+			return 1;
+
+		case 2:
+			*cpu_type = "i386/p4-ht";
+			return 1;
+	}
+#endif
+	return 0;
+}
+
+static char *get_cpu_type(void)
+{
+	char *cpu_type = "??/??";
+
+	switch (boot_cpu_data.x86_vendor) {
+		case X86_VENDOR_AMD:
+			/* Needs to be at least an Athlon (or hammer in 32bit mode) */
+			switch (boot_cpu_data.x86) {
+			case 6:
+				cpu_type = "i386/athlon";
+				break;
+			case 0xf:
+				/* Actually it could be i386/hammer too, but give
+				   user space a consistent name. */
+				cpu_type = "x86-64/hammer";
+				break;
+			}
+			break;
+		case X86_VENDOR_INTEL:
+			switch (boot_cpu_data.x86) {
+				/* Pentium IV */
+				case 0xf:
+					p4_init(&cpu_type);
+					break;
+
+				/* A P6-class processor */
+				case 6:
+					ppro_init(&cpu_type);
+					break;
+			}
+			break;
+	}
+	return cpu_type;
+}
+
+
+int __init op_perfmon_init(struct oprofile_operations * ops)
+{
+	int ret = pfm_fmt_register(&oprofile_fmt);
+	if (ret)
+		return -ENODEV;
+
+	ops->cpu_type = get_cpu_type();
+	ops->start = perfmon_start;
+	ops->stop = perfmon_stop;
+	ops->implementation = "perfmon2";
+	using_perfmon = 1;
+	printk(KERN_INFO "oprofile: using perfmon.\n");
+	return 0;
+}
+
+
+void __exit op_perfmon_exit(void)
+{
+	if (!using_perfmon)
+		return;
+
+	pfm_fmt_unregister(&oprofile_fmt);
+}
+
--- linux-2.6.base/arch/i386/oprofile/nmi_timer_int.c	2006-10-17 05:37:30.000000000 -0700
+++ linux-2.6/arch/i386/oprofile/nmi_timer_int.c	2007-01-05 06:28:08.000000000 -0800
@@ -65,6 +65,7 @@ int __init op_nmi_timer_init(struct opro
 	ops->start = timer_start;
 	ops->stop = timer_stop;
 	ops->cpu_type = "timer";
+	ops->implementation = "nmi_timer";
 	printk(KERN_INFO "oprofile: using NMI timer interrupt.\n");
 	return 0;
 }
--- linux-2.6.base/include/linux/oprofile.h	2006-10-17 05:38:30.000000000 -0700
+++ linux-2.6/include/linux/oprofile.h	2007-01-05 06:28:32.000000000 -0800
@@ -39,6 +39,8 @@ struct oprofile_operations {
 	void (*backtrace)(struct pt_regs * const regs, unsigned int depth);
 	/* CPU identification string. */
 	char * cpu_type;
+	/* Identify method of  string. */
+	char * implementation;
 };
 
 /**

