@@ -40,9 +40,13 @@ struct async_domain {
extern async_cookie_t async_schedule(async_func_t func, void *data);
extern async_cookie_t async_schedule_domain(async_func_t func, void *data,
struct async_domain *domain);
+extern async_cookie_t async_schedule_level(async_func_t func, void *data,
+ int level);
+
void async_unregister_domain(struct async_domain *domain);
extern void async_synchronize_full(void);
extern void async_synchronize_full_domain(struct async_domain *domain);
+extern void async_synchronize_level(int level);
extern void async_synchronize_cookie(async_cookie_t cookie);
extern void async_synchronize_cookie_domain(async_cookie_t cookie,
struct async_domain *domain);
@@ -282,6 +282,7 @@ void __init parse_early_options(char *cmdline);
* be one per module.
*/
#define module_init(x) __initcall(x);
+#define module_init_async(x) __initcall(x);
/**
* module_exit() - driver exit entry point
@@ -294,9 +295,12 @@ void __init parse_early_options(char *cmdline);
* There can only be one per module.
*/
#define module_exit(x) __exitcall(x);
+#define module_exit_async(x) __exitcall(x);
#else /* MODULE */
+#include <linux/async.h>
+
/*
* In most cases loadable modules do not need custom
* initcall levels. There are still some valid cases where
@@ -335,9 +339,39 @@ void __init parse_early_options(char *cmdline);
{ return exitfn; } \
void cleanup_module(void) __attribute__((alias(#exitfn)));
+#define drv_init_async(initfn, __level) \
+ static int ___init_ret; \
+ static void _drv_init_async_##initfn(void *data, async_cookie_t cookie) \
+ { \
+ initcall_t fn = data; \
+ async_synchronize_level(__level - 1); \
+ ___init_ret = fn(); \
+ if (___init_ret !=0) \
+ printk(KERN_DEBUG \
+ "async init routine failed: " #initfn "(): %d\n", ___init_ret); \
+ } \
+ static __init int __drv_init_async_##initfn(void) \
+ { \
+ async_schedule_level(_drv_init_async_##initfn, initfn, __level); \
+ return 0; \
+ } \
+ drv_init(__drv_init_async_##initfn);
+
+#define drv_exit_async(exitfn, level) \
+ static __exit void __drv_exit_async##exitfn(void) \
+ { \
+ async_synchronize_level(level); \
+ if (___init_ret == 0) \
+ exitfn(); \
+ } \
+ drv_exit(__drv_exit_async##exitfn);
+
#define module_init(initfn) drv_init(initfn);
#define module_exit(exitfn) drv_exit(exitfn);
+#define module_init_async(fn) drv_init_async(fn, 7)
+#define module_exit_async(exitfn) drv_exit_async(exitfn, 7)
+
#define __setup_param(str, unique_id, fn) /* nothing */
#define __setup(str, func) /* nothing */
#endif
@@ -68,6 +68,20 @@ static LIST_HEAD(async_global_pending); /* pending from all registered doms */
static ASYNC_DOMAIN(async_dfl_domain);
static DEFINE_SPINLOCK(async_lock);
+#define ASYNC_DOMAIN_LEVEL(level) \
+ { .pending = LIST_HEAD_INIT(async_level_domains[level-1].pending), \
+ .registered = 0 }
+
+static struct async_domain async_level_domains[] = {
+ ASYNC_DOMAIN_LEVEL(1),
+ ASYNC_DOMAIN_LEVEL(2),
+ ASYNC_DOMAIN_LEVEL(3),
+ ASYNC_DOMAIN_LEVEL(4),
+ ASYNC_DOMAIN_LEVEL(5),
+ ASYNC_DOMAIN_LEVEL(6),
+ ASYNC_DOMAIN_LEVEL(7),
+};
+
struct async_entry {
struct list_head domain_list;
struct list_head global_list;
@@ -237,6 +251,14 @@ async_cookie_t async_schedule_domain(async_func_t func, void *data,
}
EXPORT_SYMBOL_GPL(async_schedule_domain);
+async_cookie_t async_schedule_level(async_func_t func, void *data, int level)
+{
+ if (level <= 0 || level > ARRAY_SIZE(async_level_domains))
+ return __async_schedule_sync(func, data);
+ return async_schedule_domain(func, data, &async_level_domains[level-1]);
+}
+EXPORT_SYMBOL_GPL(async_schedule_level);
+
/**
* async_synchronize_full - synchronize all asynchronous function calls
*
@@ -279,6 +301,17 @@ void async_synchronize_full_domain(struct async_domain *domain)
}
EXPORT_SYMBOL_GPL(async_synchronize_full_domain);
+void async_synchronize_level(int level)
+{
+ int i;
+ if (level <= 0 || level > ARRAY_SIZE(async_level_domains))
+ return;
+
+ for (i=1; i <= level; i++)
+ async_synchronize_full_domain(&async_level_domains[i-1]);
+}
+EXPORT_SYMBOL_GPL(async_synchronize_level);
+
/**
* async_synchronize_cookie_domain - synchronize asynchronous function calls within a certain domain with cookie checkpointing
* @cookie: async_cookie_t to use as checkpoint