From: Akinobu Mita 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 Signed-off-by: Andrew Morton --- 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 #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 #include -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 #include -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 #include -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 #include -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 #include -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. _