Subject: perf, core: Introduce perf_initcall() From: Peter Zijlstra Date: Thu Nov 25 15:27:49 CET 2010 In order to initialize the built-in hardware PMU drivers before early_initcall() -- which is used by the watchdog code and expects the hardware PMUs to be present. Signed-off-by: Peter Zijlstra LKML-Reference: --- include/asm-generic/vmlinux.lds.h | 2 + include/linux/init.h | 7 +++++ init/main.c | 53 ++++++++++++++++++++++---------------- 3 files changed, 40 insertions(+), 22 deletions(-) Index: linux-2.6/include/asm-generic/vmlinux.lds.h =================================================================== --- linux-2.6.orig/include/asm-generic/vmlinux.lds.h +++ linux-2.6/include/asm-generic/vmlinux.lds.h @@ -600,6 +600,8 @@ VMLINUX_SYMBOL(__setup_end) = .; #define INITCALLS \ + *(.initcallperf.init) \ + VMLINUX_SYMBOL(__perf_initcall_end) = .; \ *(.initcallearly.init) \ VMLINUX_SYMBOL(__early_initcall_end) = .; \ *(.initcall0.init) \ Index: linux-2.6/include/linux/init.h =================================================================== --- linux-2.6.orig/include/linux/init.h +++ linux-2.6/include/linux/init.h @@ -179,6 +179,13 @@ extern int initcall_debug; __attribute__((__section__(".initcall" level ".init"))) = fn /* + * Very early initcalls, run after the perf core is up. + * + * Only for build-in code, not modules. + */ +#define perf_initcall(fn) __define_initcall("perf",fn,perf) + +/* * Early initcalls run before initializing SMP. * * Only for built-in code, not modules. Index: linux-2.6/init/main.c =================================================================== --- linux-2.6.orig/init/main.c +++ linux-2.6/init/main.c @@ -515,6 +515,36 @@ void __init __weak thread_info_cache_ini { } +extern initcall_t __initcall_start[], __initcall_end[], + __perf_initcall_end[], __early_initcall_end[]; + +static void __init do_perf_initcalls(void) +{ + initcall_t *fn; + + for (fn = __initcall_start; fn < __perf_initcall_end; fn++) + do_one_initcall(*fn); +} + +static void __init do_pre_smp_initcalls(void) +{ + initcall_t *fn; + + for (fn = __perf_initcall_end; fn < __early_initcall_end; fn++) + do_one_initcall(*fn); +} + +static void __init do_initcalls(void) +{ + initcall_t *fn; + + for (fn = __early_initcall_end; fn < __initcall_end; fn++) + do_one_initcall(*fn); + + /* Make sure there is no pending stuff from the initcall sequence */ + flush_scheduled_work(); +} + /* * Set up kernel memory allocators */ @@ -605,6 +635,7 @@ asmlinkage void __init start_kernel(void local_irq_disable(); } perf_event_init(); + do_perf_initcalls(); rcu_init(); radix_tree_init(); /* init some links before init_ISA_irqs() */ @@ -768,20 +799,6 @@ int __init_or_module do_one_initcall(ini return ret; } - -extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[]; - -static void __init do_initcalls(void) -{ - initcall_t *fn; - - for (fn = __early_initcall_end; fn < __initcall_end; fn++) - do_one_initcall(*fn); - - /* Make sure there is no pending stuff from the initcall sequence */ - flush_scheduled_work(); -} - /* * Ok, the machine is now initialized. None of the devices * have been touched yet, but the CPU subsystem is up and @@ -800,14 +817,6 @@ static void __init do_basic_setup(void) do_initcalls(); } -static void __init do_pre_smp_initcalls(void) -{ - initcall_t *fn; - - for (fn = __initcall_start; fn < __early_initcall_end; fn++) - do_one_initcall(*fn); -} - static void run_init_process(const char *init_filename) { argv_init[0] = init_filename;