blob: 062b5847897e2b78c51a939d735fa66f20fa8572 [file] [log] [blame]
Simon Glassaa4bce92022-03-04 08:43:00 -07001/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 * Events provide a general-purpose way to react to / subscribe to changes
4 * within U-Boot
5 *
6 * Copyright 2021 Google LLC
7 * Written by Simon Glass <sjg@chromium.org>
8 */
9
10#ifndef __event_h
11#define __event_h
12
Simon Glass4305fe72022-07-30 15:52:31 -060013#include <dm/ofnode_decl.h>
Christian Taedckedf369812023-07-20 09:27:24 +020014#include <linux/types.h>
Simon Glass4305fe72022-07-30 15:52:31 -060015
Simon Glassaa4bce92022-03-04 08:43:00 -070016/**
17 * enum event_t - Types of events supported by U-Boot
18 *
19 * @EVT_DM_PRE_PROBE: Device is about to be probed
20 */
21enum event_t {
22 EVT_NONE,
23 EVT_TEST,
24
Simon Glass3ee337a2022-03-04 08:43:03 -070025 /* Events related to driver model */
Simon Glass93074012023-05-04 16:50:45 -060026 EVT_DM_POST_INIT_F,
Simon Glass3ee337a2022-03-04 08:43:03 -070027 EVT_DM_PRE_PROBE,
28 EVT_DM_POST_PROBE,
29 EVT_DM_PRE_REMOVE,
30 EVT_DM_POST_REMOVE,
31
Simon Glassf1c51912022-03-04 08:43:04 -070032 /* Init hooks */
33 EVT_MISC_INIT_F,
34
Christian Taedckedf369812023-07-20 09:27:24 +020035 /* Fpga load hook */
36 EVT_FPGA_LOAD,
37
Simon Glass4305fe72022-07-30 15:52:31 -060038 /* Device tree fixups before booting */
39 EVT_FT_FIXUP,
40
Sughosh Ganub780fa52022-10-21 18:16:01 +053041 /* To be called once, before calling main_loop() */
42 EVT_MAIN_LOOP,
43
Simon Glassaa4bce92022-03-04 08:43:00 -070044 EVT_COUNT
45};
46
47union event_data {
48 /**
49 * struct event_data_test - test data
50 *
51 * @signal: A value to update the state with
52 */
53 struct event_data_test {
54 int signal;
55 } test;
Simon Glass3ee337a2022-03-04 08:43:03 -070056
57 /**
58 * struct event_dm - driver model event
59 *
60 * @dev: Device this event relates to
61 */
62 struct event_dm {
63 struct udevice *dev;
64 } dm;
Simon Glass4305fe72022-07-30 15:52:31 -060065
66 /**
Christian Taedckedf369812023-07-20 09:27:24 +020067 * struct event_fpga_load - fpga load event
68 *
69 * @buf: The buffer that was loaded into the fpga
70 * @bsize: The size of the buffer that was loaded into the fpga
71 * @result: Result of the load operation
72 */
73 struct event_fpga_load {
74 const void *buf;
75 size_t bsize;
76 int result;
77 } fpga_load;
78
79 /**
Simon Glass4305fe72022-07-30 15:52:31 -060080 * struct event_ft_fixup - FDT fixup before booting
81 *
82 * @tree: tree to update
Simon Glass74ba8e62022-09-06 20:26:58 -060083 * @images: images which are being booted
Simon Glass4305fe72022-07-30 15:52:31 -060084 */
85 struct event_ft_fixup {
86 oftree tree;
Simon Glass74ba8e62022-09-06 20:26:58 -060087 struct bootm_headers *images;
Simon Glass4305fe72022-07-30 15:52:31 -060088 } ft_fixup;
Simon Glassaa4bce92022-03-04 08:43:00 -070089};
90
91/**
92 * struct event - an event that can be sent and received
93 *
94 * @type: Event type
95 * @data: Data for this particular event
96 */
97struct event {
98 enum event_t type;
99 union event_data data;
100};
101
Simon Glass3bfbedd2023-08-21 21:16:48 -0600102/* Flags for event spy */
103enum evspy_flags {
104 EVSPYF_SIMPLE = 1 << 0,
105};
106
Simon Glassaa4bce92022-03-04 08:43:00 -0700107/** Function type for event handlers */
108typedef int (*event_handler_t)(void *ctx, struct event *event);
109
Simon Glass3bfbedd2023-08-21 21:16:48 -0600110/** Function type for simple event handlers */
111typedef int (*event_handler_simple_t)(void);
112
Simon Glassaa4bce92022-03-04 08:43:00 -0700113/**
114 * struct evspy_info - information about an event spy
115 *
116 * @func: Function to call when the event is activated (must be first)
117 * @type: Event type
Simon Glass3bfbedd2023-08-21 21:16:48 -0600118 * @flag: Flags for this spy
Simon Glassaa4bce92022-03-04 08:43:00 -0700119 * @id: Event id string
120 */
121struct evspy_info {
122 event_handler_t func;
Simon Glass3bfbedd2023-08-21 21:16:48 -0600123 u8 type;
124 u8 flags;
125#if CONFIG_IS_ENABLED(EVENT_DEBUG)
126 const char *id;
127#endif
128};
129
130/**
131 * struct evspy_info_simple - information about an event spy
132 *
133 * THis is the 'simple' record, the only difference being the handler function
134 *
135 * @func: Function to call when the event is activated (must be first)
136 * @type: Event type
137 * @flag: Flags for this spy
138 * @id: Event id string
139 */
140struct evspy_info_simple {
141 event_handler_simple_t func;
142 u8 type;
143 u8 flags;
Simon Glassaa4bce92022-03-04 08:43:00 -0700144#if CONFIG_IS_ENABLED(EVENT_DEBUG)
145 const char *id;
146#endif
147};
148
149/* Declare a new event spy */
150#if CONFIG_IS_ENABLED(EVENT_DEBUG)
Simon Glass3bfbedd2023-08-21 21:16:48 -0600151#define _ESPY_REC(_type, _func) { _func, _type, 0, #_func, }
152#define _ESPY_REC_SIMPLE(_type, _func) { _func, _type, EVSPYF_SIMPLE, #_func, }
Simon Glassaa4bce92022-03-04 08:43:00 -0700153#else
154#define _ESPY_REC(_type, _func) { _func, _type, }
Simon Glass3bfbedd2023-08-21 21:16:48 -0600155#define _ESPY_REC_SIMPLE(_type, _func) { _func, _type, EVSPYF_SIMPLE }
Simon Glassaa4bce92022-03-04 08:43:00 -0700156#endif
157
158static inline const char *event_spy_id(struct evspy_info *spy)
159{
160#if CONFIG_IS_ENABLED(EVENT_DEBUG)
161 return spy->id;
162#else
163 return "?";
164#endif
165}
166
167/*
168 * It seems that LTO will drop list entries if it decides they are not used,
169 * although the conditions that cause this are unclear.
170 *
171 * The example found is the following:
172 *
173 * static int sandbox_misc_init_f(void *ctx, struct event *event)
174 * {
175 * return sandbox_early_getopt_check();
176 * }
177 * EVENT_SPY(EVT_MISC_INIT_F, sandbox_misc_init_f);
178 *
179 * where EVENT_SPY uses ll_entry_declare()
180 *
181 * In this case, LTO decides to drop the sandbox_misc_init_f() function
182 * (which is fine) but then drops the linker-list entry too. This means
183 * that the code no longer works, in this case sandbox no-longer checks its
184 * command-line arguments properly.
185 *
186 * Without LTO, the KEEP() command in the .lds file is enough to keep the
187 * entry around. But with LTO it seems that the entry has already been
188 * dropped before the link script is considered.
189 *
190 * The only solution I can think of is to mark linker-list entries as 'used'
191 * using an attribute. This should be safe, since we don't actually want to drop
192 * any of these. However this does slightly limit LTO's optimisation choices.
Simon Glass1fd91682022-07-30 15:52:30 -0600193 *
194 * Another issue has come up, only with clang: using 'static' makes it throw
195 * away the linker-list entry sometimes, e.g. with the EVT_FT_FIXUP entry in
196 * vbe_simple.c - so for now, make it global.
Simon Glassaa4bce92022-03-04 08:43:00 -0700197 */
198#define EVENT_SPY(_type, _func) \
Simon Glassb169e212022-09-06 20:26:56 -0600199 __used ll_entry_declare(struct evspy_info, _type ## _3_ ## _func, \
200 evspy_info) = _ESPY_REC(_type, _func)
Simon Glassaa4bce92022-03-04 08:43:00 -0700201
Simon Glass3bfbedd2023-08-21 21:16:48 -0600202/* Simple spy with no function arguemnts */
203#define EVENT_SPY_SIMPLE(_type, _func) \
204 __used ll_entry_declare(struct evspy_info_simple, \
205 _type ## _3_ ## _func, \
206 evspy_info) = _ESPY_REC_SIMPLE(_type, _func)
207
Simon Glassaa4bce92022-03-04 08:43:00 -0700208/**
209 * event_register - register a new spy
210 *
211 * @id: Spy ID
212 * @type: Event type to subscribe to
213 * @func: Function to call when the event is sent
214 * @ctx: Context to pass to the function
215 * @return 0 if OK, -ve on error
216 */
217int event_register(const char *id, enum event_t type, event_handler_t func,
218 void *ctx);
219
Simon Glass3304fa82022-03-04 08:43:06 -0700220/** event_show_spy_list( - Show a list of event spies */
221void event_show_spy_list(void);
222
Simon Glassaa4bce92022-03-04 08:43:00 -0700223/**
Ovidiu Panait145f2002022-05-15 21:40:29 +0300224 * event_manual_reloc() - Relocate event handler pointers
225 *
226 * Relocate event handler pointers for all static event spies. It is called
227 * during the generic board init sequence, after relocation.
228 *
229 * Return: 0 if OK
230 */
231int event_manual_reloc(void);
232
233/**
Simon Glassd6db8942023-08-21 21:16:53 -0600234 * event_type_name() - Get the name of an event type
235 *
236 * @type: Type to check
237 * Return: Name of event, or "(unknown)" if not known
238 */
239const char *event_type_name(enum event_t type);
240
241/**
Simon Glassaa4bce92022-03-04 08:43:00 -0700242 * event_notify() - notify spies about an event
243 *
244 * It is possible to pass in union event_data here but that may not be
245 * convenient if the data is elsewhere, or is one of the members of the union.
246 * So this uses a void * for @data, with a separate @size.
247 *
248 * @type: Event type
249 * @data: Event data to be sent (e.g. union_event_data)
250 * @size: Size of data in bytes
251 * @return 0 if OK, -ve on error
252 */
253int event_notify(enum event_t type, void *data, int size);
254
Heinrich Schuchardtc95a50e2022-05-07 22:39:01 +0200255#if CONFIG_IS_ENABLED(EVENT)
Simon Glassaa4bce92022-03-04 08:43:00 -0700256/**
257 * event_notify_null() - notify spies about an event
258 *
259 * Data is NULL and the size is 0
260 *
261 * @type: Event type
262 * @return 0 if OK, -ve on error
263 */
264int event_notify_null(enum event_t type);
265#else
Simon Glassaa4bce92022-03-04 08:43:00 -0700266static inline int event_notify_null(enum event_t type)
267{
268 return 0;
269}
270#endif
271
272#if CONFIG_IS_ENABLED(EVENT_DYNAMIC)
273/**
274 * event_uninit() - Clean up dynamic events
275 *
276 * This removes all dynamic event handlers
277 */
278int event_uninit(void);
279
280/**
281 * event_uninit() - Set up dynamic events
282 *
283 * Init a list of dynamic event handlers, so that these can be added as
284 * needed
285 */
286int event_init(void);
287#else
288static inline int event_uninit(void)
289{
290 return 0;
291}
292
293static inline int event_init(void)
294{
295 return 0;
296}
297#endif
298
299#endif