
From: Akinobu Mita <amgta@yacht.ocn.ne.jp>

When some hardware setups or architectures do not allow OProfile to use
performance counters, OProfile operates in timer mode.

But, from 2.6.11-rc1, we need to specify the module parameter "timer=1" to
work on timer interrupt mode.  Change things so that we detect the absence of
the high-resolution timer and fall back to timer-based profiling
automatically.

Furthermore we can easily get oops by reading /dev/oprofile/cpu_type.

Signed-off-by: Akinobu Mita <amgta@yacht.ocn.ne.jp>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/arch/alpha/oprofile/common.c     |    6 ++++--
 25-akpm/arch/arm/oprofile/common.c       |    7 +++++--
 25-akpm/arch/arm/oprofile/init.c         |    8 ++++++--
 25-akpm/arch/i386/oprofile/init.c        |    4 +++-
 25-akpm/arch/ia64/oprofile/init.c        |    8 ++++++--
 25-akpm/arch/m32r/oprofile/init.c        |    3 ++-
 25-akpm/arch/parisc/oprofile/init.c      |    3 ++-
 25-akpm/arch/ppc64/oprofile/common.c     |    6 ++++--
 25-akpm/arch/s390/oprofile/init.c        |    3 ++-
 25-akpm/arch/sh/oprofile/op_model_null.c |    3 ++-
 25-akpm/arch/sparc64/oprofile/init.c     |    3 ++-
 25-akpm/drivers/oprofile/oprof.c         |    6 +++---
 25-akpm/include/linux/oprofile.h         |    2 +-
 13 files changed, 42 insertions(+), 20 deletions(-)

diff -puN arch/alpha/oprofile/common.c~oprofile-falling-back-on-timer-interrupt-mode arch/alpha/oprofile/common.c
--- 25/arch/alpha/oprofile/common.c~oprofile-falling-back-on-timer-interrupt-mode	2005-01-23 00:55:58.147350952 -0800
+++ 25-akpm/arch/alpha/oprofile/common.c	2005-01-23 00:55:58.167347912 -0800
@@ -138,7 +138,7 @@ op_axp_create_files(struct super_block *
 	return 0;
 }
 
-void __init
+int __init
 oprofile_arch_init(struct oprofile_operations *ops)
 {
 	struct op_axp_model *lmodel = NULL;
@@ -166,7 +166,7 @@ oprofile_arch_init(struct oprofile_opera
 	}
 
 	if (!lmodel)
-		return;
+		return -ENODEV;
 	model = lmodel;
 
 	ops->create_files = op_axp_create_files;
@@ -178,6 +178,8 @@ oprofile_arch_init(struct oprofile_opera
 
 	printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
 	       lmodel->cpu_type);
+
+	return 0;
 }
 
 
diff -puN arch/arm/oprofile/common.c~oprofile-falling-back-on-timer-interrupt-mode arch/arm/oprofile/common.c
--- 25/arch/arm/oprofile/common.c~oprofile-falling-back-on-timer-interrupt-mode	2005-01-23 00:55:58.149350648 -0800
+++ 25-akpm/arch/arm/oprofile/common.c	2005-01-23 00:55:58.167347912 -0800
@@ -105,12 +105,13 @@ static void pmu_stop(void)
 	up(&pmu_sem);
 }
 
-void __init pmu_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec)
+int __init
+pmu_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec)
 {
 	init_MUTEX(&pmu_sem);
 
 	if (spec->init() < 0)
-		return;
+		return -ENODEV;
 
 	pmu_model = spec;
 	init_driverfs();
@@ -121,6 +122,8 @@ void __init pmu_init(struct oprofile_ope
 	ops->stop = pmu_stop;
 	ops->cpu_type = pmu_model->name;
 	printk(KERN_INFO "oprofile: using %s PMU\n", spec->name);
+
+	return 0;
 }
 
 void pmu_exit(void)
diff -puN arch/arm/oprofile/init.c~oprofile-falling-back-on-timer-interrupt-mode arch/arm/oprofile/init.c
--- 25/arch/arm/oprofile/init.c~oprofile-falling-back-on-timer-interrupt-mode	2005-01-23 00:55:58.150350496 -0800
+++ 25-akpm/arch/arm/oprofile/init.c	2005-01-23 00:55:58.168347760 -0800
@@ -12,11 +12,15 @@
 #include <linux/errno.h>
 #include "op_arm_model.h"
 
-void __init oprofile_arch_init(struct oprofile_operations *ops)
+int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
+	int ret = -ENODEV;
+
 #ifdef CONFIG_CPU_XSCALE
-	pmu_init(ops, &op_xscale_spec);
+	ret = pmu_init(ops, &op_xscale_spec);
 #endif
+
+	return ret;
 }
 
 void oprofile_arch_exit(void)
diff -puN arch/i386/oprofile/init.c~oprofile-falling-back-on-timer-interrupt-mode arch/i386/oprofile/init.c
--- 25/arch/i386/oprofile/init.c~oprofile-falling-back-on-timer-interrupt-mode	2005-01-23 00:55:58.152350192 -0800
+++ 25-akpm/arch/i386/oprofile/init.c	2005-01-23 00:55:58.168347760 -0800
@@ -21,7 +21,7 @@ extern void nmi_exit(void);
 extern void x86_backtrace(struct pt_regs * const regs, unsigned int depth);
 
 
-void __init oprofile_arch_init(struct oprofile_operations * ops)
+int __init oprofile_arch_init(struct oprofile_operations * ops)
 {
 	int ret;
 
@@ -35,6 +35,8 @@ void __init oprofile_arch_init(struct op
 		ret = nmi_timer_init(ops);
 #endif
 	ops->backtrace = x86_backtrace;
+
+	return ret;
 }
 
 
diff -puN arch/ia64/oprofile/init.c~oprofile-falling-back-on-timer-interrupt-mode arch/ia64/oprofile/init.c
--- 25/arch/ia64/oprofile/init.c~oprofile-falling-back-on-timer-interrupt-mode	2005-01-23 00:55:58.153350040 -0800
+++ 25-akpm/arch/ia64/oprofile/init.c	2005-01-23 00:55:58.168347760 -0800
@@ -16,13 +16,17 @@ extern int perfmon_init(struct oprofile_
 extern void perfmon_exit(void);
 extern void ia64_backtrace(struct pt_regs * const regs, unsigned int depth);
 
-void __init oprofile_arch_init(struct oprofile_operations * ops)
+int __init oprofile_arch_init(struct oprofile_operations * ops)
 {
+	int ret = -ENODEV;
+
 #ifdef CONFIG_PERFMON
 	/* perfmon_init() can fail, but we have no way to report it */
-	perfmon_init(ops);
+	ret = perfmon_init(ops);
 #endif
 	ops->backtrace = ia64_backtrace;
+
+	return ret;
 }
 
 
diff -puN arch/m32r/oprofile/init.c~oprofile-falling-back-on-timer-interrupt-mode arch/m32r/oprofile/init.c
--- 25/arch/m32r/oprofile/init.c~oprofile-falling-back-on-timer-interrupt-mode	2005-01-23 00:55:58.154349888 -0800
+++ 25-akpm/arch/m32r/oprofile/init.c	2005-01-23 00:55:58.169347608 -0800
@@ -12,8 +12,9 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 
-void __init oprofile_arch_init(struct oprofile_operations * ops)
+int __init oprofile_arch_init(struct oprofile_operations * ops)
 {
+	return -ENODEV;
 }
 
 void oprofile_arch_exit(void)
diff -puN arch/parisc/oprofile/init.c~oprofile-falling-back-on-timer-interrupt-mode arch/parisc/oprofile/init.c
--- 25/arch/parisc/oprofile/init.c~oprofile-falling-back-on-timer-interrupt-mode	2005-01-23 00:55:58.156349584 -0800
+++ 25-akpm/arch/parisc/oprofile/init.c	2005-01-23 00:55:58.169347608 -0800
@@ -12,8 +12,9 @@
 #include <linux/kernel.h>
 #include <linux/oprofile.h>
 
-void __init oprofile_arch_init(struct oprofile_operations * ops)
+int __init oprofile_arch_init(struct oprofile_operations * ops)
 {
+	return -ENODEV;
 }
 
 
diff -puN arch/ppc64/oprofile/common.c~oprofile-falling-back-on-timer-interrupt-mode arch/ppc64/oprofile/common.c
--- 25/arch/ppc64/oprofile/common.c~oprofile-falling-back-on-timer-interrupt-mode	2005-01-23 00:55:58.157349432 -0800
+++ 25-akpm/arch/ppc64/oprofile/common.c	2005-01-23 00:55:58.169347608 -0800
@@ -125,7 +125,7 @@ static int op_ppc64_create_files(struct 
 	return 0;
 }
 
-void __init oprofile_arch_init(struct oprofile_operations *ops)
+int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
 	unsigned int pvr;
 
@@ -170,7 +170,7 @@ void __init oprofile_arch_init(struct op
 			break;
 
 		default:
-			return;
+			return -ENODEV;
 	}
 
 	ops->create_files = op_ppc64_create_files;
@@ -181,6 +181,8 @@ void __init oprofile_arch_init(struct op
 
 	printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
 	       ops->cpu_type);
+
+	return 0;
 }
 
 void oprofile_arch_exit(void)
diff -puN arch/s390/oprofile/init.c~oprofile-falling-back-on-timer-interrupt-mode arch/s390/oprofile/init.c
--- 25/arch/s390/oprofile/init.c~oprofile-falling-back-on-timer-interrupt-mode	2005-01-23 00:55:58.158349280 -0800
+++ 25-akpm/arch/s390/oprofile/init.c	2005-01-23 00:55:58.170347456 -0800
@@ -12,8 +12,9 @@
 #include <linux/init.h>
 #include <linux/errno.h>
 
-void __init oprofile_arch_init(struct oprofile_operations* ops)
+int __init oprofile_arch_init(struct oprofile_operations* ops)
 {
+	return -ENODEV;
 }
 
 void oprofile_arch_exit(void)
diff -puN arch/sh/oprofile/op_model_null.c~oprofile-falling-back-on-timer-interrupt-mode arch/sh/oprofile/op_model_null.c
--- 25/arch/sh/oprofile/op_model_null.c~oprofile-falling-back-on-timer-interrupt-mode	2005-01-23 00:55:58.160348976 -0800
+++ 25-akpm/arch/sh/oprofile/op_model_null.c	2005-01-23 00:55:58.170347456 -0800
@@ -12,8 +12,9 @@
 #include <linux/init.h>
 #include <linux/errno.h>
 
-void __init oprofile_arch_init(struct oprofile_operations *ops)
+int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
+	return -ENODEV;
 }
 
 void oprofile_arch_exit(void)
diff -puN arch/sparc64/oprofile/init.c~oprofile-falling-back-on-timer-interrupt-mode arch/sparc64/oprofile/init.c
--- 25/arch/sparc64/oprofile/init.c~oprofile-falling-back-on-timer-interrupt-mode	2005-01-23 00:55:58.161348824 -0800
+++ 25-akpm/arch/sparc64/oprofile/init.c	2005-01-23 00:55:58.170347456 -0800
@@ -12,8 +12,9 @@
 #include <linux/errno.h>
 #include <linux/init.h>
  
-void __init oprofile_arch_init(struct oprofile_operations * ops)
+int __init oprofile_arch_init(struct oprofile_operations * ops)
 {
+	return -ENODEV;
 }
 
 
diff -puN drivers/oprofile/oprof.c~oprofile-falling-back-on-timer-interrupt-mode drivers/oprofile/oprof.c
--- 25/drivers/oprofile/oprof.c~oprofile-falling-back-on-timer-interrupt-mode	2005-01-23 00:55:58.162348672 -0800
+++ 25-akpm/drivers/oprofile/oprof.c	2005-01-23 00:55:58.171347304 -0800
@@ -153,11 +153,11 @@ out:
 
 static int __init oprofile_init(void)
 {
-	int err = 0;
+	int err;
 
-	oprofile_arch_init(&oprofile_ops);
+	err = oprofile_arch_init(&oprofile_ops);
 
-	if (timer) {
+	if (err < 0 || timer) {
 		printk(KERN_INFO "oprofile: using timer interrupt.\n");
 		oprofile_timer_init(&oprofile_ops);
 	}
diff -puN include/linux/oprofile.h~oprofile-falling-back-on-timer-interrupt-mode include/linux/oprofile.h
--- 25/include/linux/oprofile.h~oprofile-falling-back-on-timer-interrupt-mode	2005-01-23 00:55:58.163348520 -0800
+++ 25-akpm/include/linux/oprofile.h	2005-01-23 00:55:58.171347304 -0800
@@ -48,7 +48,7 @@ struct oprofile_operations {
  *
  * If an error occurs, the fields should be left untouched.
  */
-void oprofile_arch_init(struct oprofile_operations * ops);
+int oprofile_arch_init(struct oprofile_operations * ops);
  
 /**
  * One-time exit/cleanup for the arch.
_
