]> code.ossystems Code Review - openembedded-core.git/blob
7c19053b0e5483f8c8b837be5982b76ba44d57e3
[openembedded-core.git] /
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
5
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.
11
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.
16
17 Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
18 Signed-off-by: Ingo Molnar <mingo@elte.hu>
19 ---
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(-)
24
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
29 @@ -372,6 +372,9 @@
30         *(.initcall5.init)                                              \
31         *(.initcall5s.init)                                             \
32         *(.initcallrootfs.init)                                         \
33 +       __async_initcall_start = .;                                     \
34 +       *(.initcall6a.init)                                             \
35 +       __async_initcall_end = .;                                       \
36         *(.initcall6.init)                                              \
37         *(.initcall6s.init)                                             \
38         *(.initcall7.init)                                              \
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
43 @@ -197,11 +197,13 @@
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)
51  
52  #define __initcall(fn) device_initcall(fn)
53 +#define __initcall_async(fn) device_initcall_async(fn)
54  
55  #define __exitcall(fn) \
56         static exitcall_t __exitcall_##fn __exit_call = fn
57 @@ -257,6 +259,7 @@
58   * be one per module.
59   */
60  #define module_init(x) __initcall(x);
61 +#define module_init_async(x)   __initcall_async(x);
62  
63  /**
64   * module_exit() - driver exit entry point
65 @@ -279,10 +282,13 @@
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)
71  
72  #define security_initcall(fn)          module_init(fn)
73  
74 +#define module_init_async(fn)          module_init(fn)
75 +
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
81 --- a/init/main.c
82 +++ b/init/main.c
83 @@ -746,18 +746,47 @@
84  
85  
86  extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];
87 +extern initcall_t __async_initcall_start[], __async_initcall_end[];
88  
89 -static void __init do_initcalls(void)
90 +static void __init do_async_initcalls(struct work_struct *dummy)
91  {
92         initcall_t *call;
93  
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);
97 +}
98 +
99 +static struct workqueue_struct *async_init_wq;
100 +
101 +static void __init do_initcalls(void)
102 +{
103 +       initcall_t *call;
104 +       static DECLARE_WORK(async_work, do_async_initcalls);
105 +       int phase = 0; /* 0 = levels 0 - 6, 1 = level 6a, 2 = after level 6a */
106 +
107 +       async_init_wq = create_singlethread_workqueue("kasyncinit");
108 +
109 +       for (call = __early_initcall_end; call < __initcall_end; call++) {
110 +               if (phase == 0 && call >= __async_initcall_start) {
111 +                       phase = 1;
112 +                       queue_work(async_init_wq, &async_work);
113 +               }
114 +               if (phase == 1 && call >= __async_initcall_end)
115 +                       phase = 2;
116 +               if (phase != 1)
117 +                       do_one_initcall(*call);
118 +       }
119  
120 -       /* Make sure there is no pending stuff from the initcall sequence */
121 +       /*
122 +       * Make sure there is no pending stuff from the initcall sequence,
123 +       * including the async initcalls
124 +       */
125         flush_scheduled_work();
126 +       flush_workqueue(async_init_wq);
127 +       destroy_workqueue(async_init_wq);
128  }
129  
130 +
131  /*
132   * Ok, the machine is now initialized. None of the devices
133   * have been touched yet, but the CPU subsystem is up and
134 -- 
135 1.5.4.3
136