1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | /* |
3 | * async.h: Asynchronous function calls for boot performance |
4 | * |
5 | * (C) Copyright 2009 Intel Corporation |
6 | * Author: Arjan van de Ven <arjan@linux.intel.com> |
7 | */ |
8 | #ifndef __ASYNC_H__ |
9 | #define __ASYNC_H__ |
10 | |
11 | #include <linux/types.h> |
12 | #include <linux/list.h> |
13 | #include <linux/numa.h> |
14 | #include <linux/device.h> |
15 | |
16 | typedef u64 async_cookie_t; |
17 | typedef void (*async_func_t) (void *data, async_cookie_t cookie); |
18 | struct async_domain { |
19 | struct list_head pending; |
20 | unsigned registered:1; |
21 | }; |
22 | |
23 | /* |
24 | * domain participates in global async_synchronize_full |
25 | */ |
26 | #define ASYNC_DOMAIN(_name) \ |
27 | struct async_domain _name = { .pending = LIST_HEAD_INIT(_name.pending), \ |
28 | .registered = 1 } |
29 | |
30 | /* |
31 | * domain is free to go out of scope as soon as all pending work is |
32 | * complete, this domain does not participate in async_synchronize_full |
33 | */ |
34 | #define ASYNC_DOMAIN_EXCLUSIVE(_name) \ |
35 | struct async_domain _name = { .pending = LIST_HEAD_INIT(_name.pending), \ |
36 | .registered = 0 } |
37 | |
38 | async_cookie_t async_schedule_node(async_func_t func, void *data, |
39 | int node); |
40 | async_cookie_t async_schedule_node_domain(async_func_t func, void *data, |
41 | int node, |
42 | struct async_domain *domain); |
43 | |
44 | /** |
45 | * async_schedule - schedule a function for asynchronous execution |
46 | * @func: function to execute asynchronously |
47 | * @data: data pointer to pass to the function |
48 | * |
49 | * Returns an async_cookie_t that may be used for checkpointing later. |
50 | * Note: This function may be called from atomic or non-atomic contexts. |
51 | */ |
52 | static inline async_cookie_t async_schedule(async_func_t func, void *data) |
53 | { |
54 | return async_schedule_node(func, data, NUMA_NO_NODE); |
55 | } |
56 | |
57 | /** |
58 | * async_schedule_domain - schedule a function for asynchronous execution within a certain domain |
59 | * @func: function to execute asynchronously |
60 | * @data: data pointer to pass to the function |
61 | * @domain: the domain |
62 | * |
63 | * Returns an async_cookie_t that may be used for checkpointing later. |
64 | * @domain may be used in the async_synchronize_*_domain() functions to |
65 | * wait within a certain synchronization domain rather than globally. |
66 | * Note: This function may be called from atomic or non-atomic contexts. |
67 | */ |
68 | static inline async_cookie_t |
69 | async_schedule_domain(async_func_t func, void *data, |
70 | struct async_domain *domain) |
71 | { |
72 | return async_schedule_node_domain(func, data, NUMA_NO_NODE, domain); |
73 | } |
74 | |
75 | /** |
76 | * async_schedule_dev - A device specific version of async_schedule |
77 | * @func: function to execute asynchronously |
78 | * @dev: device argument to be passed to function |
79 | * |
80 | * Returns an async_cookie_t that may be used for checkpointing later. |
81 | * @dev is used as both the argument for the function and to provide NUMA |
82 | * context for where to run the function. By doing this we can try to |
83 | * provide for the best possible outcome by operating on the device on the |
84 | * CPUs closest to the device. |
85 | * Note: This function may be called from atomic or non-atomic contexts. |
86 | */ |
87 | static inline async_cookie_t |
88 | async_schedule_dev(async_func_t func, struct device *dev) |
89 | { |
90 | return async_schedule_node(func, data: dev, node: dev_to_node(dev)); |
91 | } |
92 | |
93 | /** |
94 | * async_schedule_dev_domain - A device specific version of async_schedule_domain |
95 | * @func: function to execute asynchronously |
96 | * @dev: device argument to be passed to function |
97 | * @domain: the domain |
98 | * |
99 | * Returns an async_cookie_t that may be used for checkpointing later. |
100 | * @dev is used as both the argument for the function and to provide NUMA |
101 | * context for where to run the function. By doing this we can try to |
102 | * provide for the best possible outcome by operating on the device on the |
103 | * CPUs closest to the device. |
104 | * @domain may be used in the async_synchronize_*_domain() functions to |
105 | * wait within a certain synchronization domain rather than globally. |
106 | * Note: This function may be called from atomic or non-atomic contexts. |
107 | */ |
108 | static inline async_cookie_t |
109 | async_schedule_dev_domain(async_func_t func, struct device *dev, |
110 | struct async_domain *domain) |
111 | { |
112 | return async_schedule_node_domain(func, data: dev, node: dev_to_node(dev), domain); |
113 | } |
114 | |
115 | extern void async_synchronize_full(void); |
116 | extern void async_synchronize_full_domain(struct async_domain *domain); |
117 | extern void async_synchronize_cookie(async_cookie_t cookie); |
118 | extern void async_synchronize_cookie_domain(async_cookie_t cookie, |
119 | struct async_domain *domain); |
120 | extern bool current_is_async(void); |
121 | #endif |
122 | |