1 From ac9103dd8e4dc65c110d6cba9a3380c6c617ffa7 Mon Sep 17 00:00:00 2001
2 From: Arjan van de Ven <arjan@linux.intel.com>
3 Date: Fri, 18 Jul 2008 15:16:08 -0700
4 Subject: [PATCH] fastboot: create a "asynchronous" initlevel
6 This patch creates an asynchronous initlevel (6a) which is at the same
7 level as the normal device initcalls, but with the difference that they
8 are run asynchronous from all the other initcalls. The purpose of this
9 *selective* level is that we can move long waiting inits that are not
10 boot-critical to this level one at a time.
12 To keep things not totally insane, the asynchronous initcalls are async
13 to the other initcalls, but are still ordered to themselves; think of it
14 as "bottom-half-not-softirq". This has the benefit that async drivers
15 still have stable device ordering between them.
17 Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
18 Signed-off-by: Ingo Molnar <mingo@elte.hu>
20 include/asm-generic/vmlinux.lds.h | 3 +++
21 include/linux/init.h | 6 ++++++
22 init/main.c | 36 +++++++++++++++++++++++++++++++++---
23 3 files changed, 42 insertions(+), 3 deletions(-)
25 diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
26 index 729f6b0..39c1afc 100644
27 --- a/include/asm-generic/vmlinux.lds.h
28 +++ b/include/asm-generic/vmlinux.lds.h
32 *(.initcallrootfs.init) \
33 + __async_initcall_start = .; \
34 + *(.initcall6a.init) \
35 + __async_initcall_end = .; \
39 diff --git a/include/linux/init.h b/include/linux/init.h
40 index 21d658c..75db909 100644
41 --- a/include/linux/init.h
42 +++ b/include/linux/init.h
44 #define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)
45 #define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)
46 #define device_initcall(fn) __define_initcall("6",fn,6)
47 +#define device_initcall_async(fn) __define_initcall("6a", fn, 6a)
48 #define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
49 #define late_initcall(fn) __define_initcall("7",fn,7)
50 #define late_initcall_sync(fn) __define_initcall("7s",fn,7s)
52 #define __initcall(fn) device_initcall(fn)
53 +#define __initcall_async(fn) device_initcall_async(fn)
55 #define __exitcall(fn) \
56 static exitcall_t __exitcall_##fn __exit_call = fn
60 #define module_init(x) __initcall(x);
61 +#define module_init_async(x) __initcall_async(x);
64 * module_exit() - driver exit entry point
66 #define subsys_initcall(fn) module_init(fn)
67 #define fs_initcall(fn) module_init(fn)
68 #define device_initcall(fn) module_init(fn)
69 +#define device_initcall_async(fn) module_init(fn)
70 #define late_initcall(fn) module_init(fn)
72 #define security_initcall(fn) module_init(fn)
74 +#define module_init_async(fn) module_init(fn)
76 /* Each module must use one module_init(). */
77 #define module_init(initfn) \
78 static inline initcall_t __inittest(void) \
79 diff --git a/init/main.c b/init/main.c
80 index edeace0..6961de2 100644
86 extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];
87 +extern initcall_t __async_initcall_start[], __async_initcall_end[];
89 -static void __init do_initcalls(void)
90 +static void __init do_async_initcalls(struct work_struct *dummy)
94 - for (call = __early_initcall_end; call < __initcall_end; call++)
95 + for (call = __async_initcall_start; call < __async_initcall_end; call++)
96 do_one_initcall(*call);
99 +static struct workqueue_struct *async_init_wq;
101 +static void __init do_initcalls(void)
104 + static DECLARE_WORK(async_work, do_async_initcalls);
105 + int phase = 0; /* 0 = levels 0 - 6, 1 = level 6a, 2 = after level 6a */
107 + async_init_wq = create_singlethread_workqueue("kasyncinit");
109 + for (call = __early_initcall_end; call < __initcall_end; call++) {
110 + if (phase == 0 && call >= __async_initcall_start) {
112 + queue_work(async_init_wq, &async_work);
114 + if (phase == 1 && call >= __async_initcall_end)
117 + do_one_initcall(*call);
120 - /* Make sure there is no pending stuff from the initcall sequence */
122 + * Make sure there is no pending stuff from the initcall sequence,
123 + * including the async initcalls
125 flush_scheduled_work();
126 + flush_workqueue(async_init_wq);
127 + destroy_workqueue(async_init_wq);
132 * Ok, the machine is now initialized. None of the devices
133 * have been touched yet, but the CPU subsystem is up and