blob: daf44bf8a83b2ec2edcee981c23bed16df78df5d [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
102/** Function type for event handlers */
103typedef int (*event_handler_t)(void *ctx, struct event *event);
104
105/**
106 * struct evspy_info - information about an event spy
107 *
108 * @func: Function to call when the event is activated (must be first)
109 * @type: Event type
110 * @id: Event id string
111 */
112struct evspy_info {
113 event_handler_t func;
114 enum event_t type;
115#if CONFIG_IS_ENABLED(EVENT_DEBUG)
116 const char *id;
117#endif
118};
119
120/* Declare a new event spy */
121#if CONFIG_IS_ENABLED(EVENT_DEBUG)
122#define _ESPY_REC(_type, _func) { _func, _type, #_func, }
123#else
124#define _ESPY_REC(_type, _func) { _func, _type, }
125#endif
126
127static inline const char *event_spy_id(struct evspy_info *spy)
128{
129#if CONFIG_IS_ENABLED(EVENT_DEBUG)
130 return spy->id;
131#else
132 return "?";
133#endif
134}
135
136/*
137 * It seems that LTO will drop list entries if it decides they are not used,
138 * although the conditions that cause this are unclear.
139 *
140 * The example found is the following:
141 *
142 * static int sandbox_misc_init_f(void *ctx, struct event *event)
143 * {
144 * return sandbox_early_getopt_check();
145 * }
146 * EVENT_SPY(EVT_MISC_INIT_F, sandbox_misc_init_f);
147 *
148 * where EVENT_SPY uses ll_entry_declare()
149 *
150 * In this case, LTO decides to drop the sandbox_misc_init_f() function
151 * (which is fine) but then drops the linker-list entry too. This means
152 * that the code no longer works, in this case sandbox no-longer checks its
153 * command-line arguments properly.
154 *
155 * Without LTO, the KEEP() command in the .lds file is enough to keep the
156 * entry around. But with LTO it seems that the entry has already been
157 * dropped before the link script is considered.
158 *
159 * The only solution I can think of is to mark linker-list entries as 'used'
160 * using an attribute. This should be safe, since we don't actually want to drop
161 * any of these. However this does slightly limit LTO's optimisation choices.
Simon Glass1fd91682022-07-30 15:52:30 -0600162 *
163 * Another issue has come up, only with clang: using 'static' makes it throw
164 * away the linker-list entry sometimes, e.g. with the EVT_FT_FIXUP entry in
165 * vbe_simple.c - so for now, make it global.
Simon Glassaa4bce92022-03-04 08:43:00 -0700166 */
167#define EVENT_SPY(_type, _func) \
Simon Glassb169e212022-09-06 20:26:56 -0600168 __used ll_entry_declare(struct evspy_info, _type ## _3_ ## _func, \
169 evspy_info) = _ESPY_REC(_type, _func)
Simon Glassaa4bce92022-03-04 08:43:00 -0700170
171/**
172 * event_register - register a new spy
173 *
174 * @id: Spy ID
175 * @type: Event type to subscribe to
176 * @func: Function to call when the event is sent
177 * @ctx: Context to pass to the function
178 * @return 0 if OK, -ve on error
179 */
180int event_register(const char *id, enum event_t type, event_handler_t func,
181 void *ctx);
182
Simon Glass3304fa82022-03-04 08:43:06 -0700183/** event_show_spy_list( - Show a list of event spies */
184void event_show_spy_list(void);
185
Simon Glassaa4bce92022-03-04 08:43:00 -0700186/**
Ovidiu Panait145f2002022-05-15 21:40:29 +0300187 * event_manual_reloc() - Relocate event handler pointers
188 *
189 * Relocate event handler pointers for all static event spies. It is called
190 * during the generic board init sequence, after relocation.
191 *
192 * Return: 0 if OK
193 */
194int event_manual_reloc(void);
195
196/**
Simon Glassaa4bce92022-03-04 08:43:00 -0700197 * event_notify() - notify spies about an event
198 *
199 * It is possible to pass in union event_data here but that may not be
200 * convenient if the data is elsewhere, or is one of the members of the union.
201 * So this uses a void * for @data, with a separate @size.
202 *
203 * @type: Event type
204 * @data: Event data to be sent (e.g. union_event_data)
205 * @size: Size of data in bytes
206 * @return 0 if OK, -ve on error
207 */
208int event_notify(enum event_t type, void *data, int size);
209
Heinrich Schuchardtc95a50e2022-05-07 22:39:01 +0200210#if CONFIG_IS_ENABLED(EVENT)
Simon Glassaa4bce92022-03-04 08:43:00 -0700211/**
212 * event_notify_null() - notify spies about an event
213 *
214 * Data is NULL and the size is 0
215 *
216 * @type: Event type
217 * @return 0 if OK, -ve on error
218 */
219int event_notify_null(enum event_t type);
220#else
Simon Glassaa4bce92022-03-04 08:43:00 -0700221static inline int event_notify_null(enum event_t type)
222{
223 return 0;
224}
225#endif
226
227#if CONFIG_IS_ENABLED(EVENT_DYNAMIC)
228/**
229 * event_uninit() - Clean up dynamic events
230 *
231 * This removes all dynamic event handlers
232 */
233int event_uninit(void);
234
235/**
236 * event_uninit() - Set up dynamic events
237 *
238 * Init a list of dynamic event handlers, so that these can be added as
239 * needed
240 */
241int event_init(void);
242#else
243static inline int event_uninit(void)
244{
245 return 0;
246}
247
248static inline int event_init(void)
249{
250 return 0;
251}
252#endif
253
254#endif