blob: 747a9f6c654bbdef101129e3ee435142df28420c [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
Simon Glassfcebb7b2023-08-21 21:16:59 -060035 /*
36 * Emitted before relocation to set up Firmware Support Package
37 *
38 * Where U-Boot relies on binary blobs to handle part of the system
39 * init, this event can be used to set up the blobs. This is used on
40 * some Intel platforms
41 */
42 EVT_FSP_INIT_F,
43
Simon Glass1cedca12023-08-21 21:17:01 -060044 /*
45 * Emitted just before jumping to the main loop
46 *
47 * Some boards need to perform initialisation immediately before control
48 * is passed to the command-line interpreter (e.g. for init that depend
49 * on later phases in the init sequence).
50 *
51 * Some parts can be only initialized if all others (like Interrupts)
52 * are up and running (e.g. the PC-style ISA keyboard).
53 */
54 EVT_LAST_STAGE_INIT,
55
Christian Taedckedf369812023-07-20 09:27:24 +020056 /* Fpga load hook */
57 EVT_FPGA_LOAD,
58
Simon Glass4305fe72022-07-30 15:52:31 -060059 /* Device tree fixups before booting */
60 EVT_FT_FIXUP,
61
Sughosh Ganub780fa52022-10-21 18:16:01 +053062 /* To be called once, before calling main_loop() */
63 EVT_MAIN_LOOP,
64
Simon Glassaa4bce92022-03-04 08:43:00 -070065 EVT_COUNT
66};
67
68union event_data {
69 /**
70 * struct event_data_test - test data
71 *
72 * @signal: A value to update the state with
73 */
74 struct event_data_test {
75 int signal;
76 } test;
Simon Glass3ee337a2022-03-04 08:43:03 -070077
78 /**
79 * struct event_dm - driver model event
80 *
81 * @dev: Device this event relates to
82 */
83 struct event_dm {
84 struct udevice *dev;
85 } dm;
Simon Glass4305fe72022-07-30 15:52:31 -060086
87 /**
Christian Taedckedf369812023-07-20 09:27:24 +020088 * struct event_fpga_load - fpga load event
89 *
90 * @buf: The buffer that was loaded into the fpga
91 * @bsize: The size of the buffer that was loaded into the fpga
92 * @result: Result of the load operation
93 */
94 struct event_fpga_load {
95 const void *buf;
96 size_t bsize;
97 int result;
98 } fpga_load;
99
100 /**
Simon Glass4305fe72022-07-30 15:52:31 -0600101 * struct event_ft_fixup - FDT fixup before booting
102 *
103 * @tree: tree to update
Simon Glass74ba8e62022-09-06 20:26:58 -0600104 * @images: images which are being booted
Simon Glass4305fe72022-07-30 15:52:31 -0600105 */
106 struct event_ft_fixup {
107 oftree tree;
Simon Glass74ba8e62022-09-06 20:26:58 -0600108 struct bootm_headers *images;
Simon Glass4305fe72022-07-30 15:52:31 -0600109 } ft_fixup;
Simon Glassaa4bce92022-03-04 08:43:00 -0700110};
111
112/**
113 * struct event - an event that can be sent and received
114 *
115 * @type: Event type
116 * @data: Data for this particular event
117 */
118struct event {
119 enum event_t type;
120 union event_data data;
121};
122
Simon Glass3bfbedd2023-08-21 21:16:48 -0600123/* Flags for event spy */
124enum evspy_flags {
125 EVSPYF_SIMPLE = 1 << 0,
126};
127
Simon Glassaa4bce92022-03-04 08:43:00 -0700128/** Function type for event handlers */
129typedef int (*event_handler_t)(void *ctx, struct event *event);
130
Simon Glass3bfbedd2023-08-21 21:16:48 -0600131/** Function type for simple event handlers */
132typedef int (*event_handler_simple_t)(void);
133
Simon Glassaa4bce92022-03-04 08:43:00 -0700134/**
135 * struct evspy_info - information about an event spy
136 *
137 * @func: Function to call when the event is activated (must be first)
138 * @type: Event type
Simon Glass3bfbedd2023-08-21 21:16:48 -0600139 * @flag: Flags for this spy
Simon Glassaa4bce92022-03-04 08:43:00 -0700140 * @id: Event id string
141 */
142struct evspy_info {
143 event_handler_t func;
Simon Glass3bfbedd2023-08-21 21:16:48 -0600144 u8 type;
145 u8 flags;
146#if CONFIG_IS_ENABLED(EVENT_DEBUG)
147 const char *id;
148#endif
149};
150
151/**
152 * struct evspy_info_simple - information about an event spy
153 *
154 * THis is the 'simple' record, the only difference being the handler function
155 *
156 * @func: Function to call when the event is activated (must be first)
157 * @type: Event type
158 * @flag: Flags for this spy
159 * @id: Event id string
160 */
161struct evspy_info_simple {
162 event_handler_simple_t func;
163 u8 type;
164 u8 flags;
Simon Glassaa4bce92022-03-04 08:43:00 -0700165#if CONFIG_IS_ENABLED(EVENT_DEBUG)
166 const char *id;
167#endif
168};
169
170/* Declare a new event spy */
171#if CONFIG_IS_ENABLED(EVENT_DEBUG)
Simon Glass3bfbedd2023-08-21 21:16:48 -0600172#define _ESPY_REC(_type, _func) { _func, _type, 0, #_func, }
173#define _ESPY_REC_SIMPLE(_type, _func) { _func, _type, EVSPYF_SIMPLE, #_func, }
Simon Glassaa4bce92022-03-04 08:43:00 -0700174#else
175#define _ESPY_REC(_type, _func) { _func, _type, }
Simon Glass3bfbedd2023-08-21 21:16:48 -0600176#define _ESPY_REC_SIMPLE(_type, _func) { _func, _type, EVSPYF_SIMPLE }
Simon Glassaa4bce92022-03-04 08:43:00 -0700177#endif
178
179static inline const char *event_spy_id(struct evspy_info *spy)
180{
181#if CONFIG_IS_ENABLED(EVENT_DEBUG)
182 return spy->id;
183#else
184 return "?";
185#endif
186}
187
188/*
189 * It seems that LTO will drop list entries if it decides they are not used,
190 * although the conditions that cause this are unclear.
191 *
192 * The example found is the following:
193 *
194 * static int sandbox_misc_init_f(void *ctx, struct event *event)
195 * {
196 * return sandbox_early_getopt_check();
197 * }
198 * EVENT_SPY(EVT_MISC_INIT_F, sandbox_misc_init_f);
199 *
200 * where EVENT_SPY uses ll_entry_declare()
201 *
202 * In this case, LTO decides to drop the sandbox_misc_init_f() function
203 * (which is fine) but then drops the linker-list entry too. This means
204 * that the code no longer works, in this case sandbox no-longer checks its
205 * command-line arguments properly.
206 *
207 * Without LTO, the KEEP() command in the .lds file is enough to keep the
208 * entry around. But with LTO it seems that the entry has already been
209 * dropped before the link script is considered.
210 *
211 * The only solution I can think of is to mark linker-list entries as 'used'
212 * using an attribute. This should be safe, since we don't actually want to drop
213 * any of these. However this does slightly limit LTO's optimisation choices.
Simon Glass1fd91682022-07-30 15:52:30 -0600214 *
215 * Another issue has come up, only with clang: using 'static' makes it throw
216 * away the linker-list entry sometimes, e.g. with the EVT_FT_FIXUP entry in
217 * vbe_simple.c - so for now, make it global.
Simon Glassaa4bce92022-03-04 08:43:00 -0700218 */
Simon Glassa41134f2023-08-21 21:16:57 -0600219#define EVENT_SPY_FULL(_type, _func) \
Simon Glassb169e212022-09-06 20:26:56 -0600220 __used ll_entry_declare(struct evspy_info, _type ## _3_ ## _func, \
221 evspy_info) = _ESPY_REC(_type, _func)
Simon Glassaa4bce92022-03-04 08:43:00 -0700222
Simon Glass3bfbedd2023-08-21 21:16:48 -0600223/* Simple spy with no function arguemnts */
224#define EVENT_SPY_SIMPLE(_type, _func) \
225 __used ll_entry_declare(struct evspy_info_simple, \
226 _type ## _3_ ## _func, \
227 evspy_info) = _ESPY_REC_SIMPLE(_type, _func)
228
Simon Glassaa4bce92022-03-04 08:43:00 -0700229/**
230 * event_register - register a new spy
231 *
232 * @id: Spy ID
233 * @type: Event type to subscribe to
234 * @func: Function to call when the event is sent
235 * @ctx: Context to pass to the function
236 * @return 0 if OK, -ve on error
237 */
238int event_register(const char *id, enum event_t type, event_handler_t func,
239 void *ctx);
240
Simon Glass3304fa82022-03-04 08:43:06 -0700241/** event_show_spy_list( - Show a list of event spies */
242void event_show_spy_list(void);
243
Simon Glassaa4bce92022-03-04 08:43:00 -0700244/**
Ovidiu Panait145f2002022-05-15 21:40:29 +0300245 * event_manual_reloc() - Relocate event handler pointers
246 *
247 * Relocate event handler pointers for all static event spies. It is called
248 * during the generic board init sequence, after relocation.
249 *
250 * Return: 0 if OK
251 */
252int event_manual_reloc(void);
253
254/**
Simon Glassd6db8942023-08-21 21:16:53 -0600255 * event_type_name() - Get the name of an event type
256 *
257 * @type: Type to check
258 * Return: Name of event, or "(unknown)" if not known
259 */
260const char *event_type_name(enum event_t type);
261
262/**
Simon Glassaa4bce92022-03-04 08:43:00 -0700263 * event_notify() - notify spies about an event
264 *
265 * It is possible to pass in union event_data here but that may not be
266 * convenient if the data is elsewhere, or is one of the members of the union.
267 * So this uses a void * for @data, with a separate @size.
268 *
269 * @type: Event type
270 * @data: Event data to be sent (e.g. union_event_data)
271 * @size: Size of data in bytes
272 * @return 0 if OK, -ve on error
273 */
274int event_notify(enum event_t type, void *data, int size);
275
Heinrich Schuchardtc95a50e2022-05-07 22:39:01 +0200276#if CONFIG_IS_ENABLED(EVENT)
Simon Glassaa4bce92022-03-04 08:43:00 -0700277/**
278 * event_notify_null() - notify spies about an event
279 *
280 * Data is NULL and the size is 0
281 *
282 * @type: Event type
283 * @return 0 if OK, -ve on error
284 */
285int event_notify_null(enum event_t type);
286#else
Simon Glassaa4bce92022-03-04 08:43:00 -0700287static inline int event_notify_null(enum event_t type)
288{
289 return 0;
290}
291#endif
292
293#if CONFIG_IS_ENABLED(EVENT_DYNAMIC)
294/**
295 * event_uninit() - Clean up dynamic events
296 *
297 * This removes all dynamic event handlers
298 */
299int event_uninit(void);
300
301/**
302 * event_uninit() - Set up dynamic events
303 *
304 * Init a list of dynamic event handlers, so that these can be added as
305 * needed
306 */
307int event_init(void);
308#else
309static inline int event_uninit(void)
310{
311 return 0;
312}
313
314static inline int event_init(void)
315{
316 return 0;
317}
318#endif
319
320#endif