1/* 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 13#include <dm/ofnode_decl.h> 14#include <linux/types.h> 15 16/** 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 /** 23 * @EVT_NONE: This zero value is not used for events. 24 */ 25 EVT_NONE = 0, 26 27 /** 28 * @EVT_TEST: This event is used in unit tests. 29 */ 30 EVT_TEST, 31 32 /** 33 * @EVT_DM_POST_INIT_F: 34 * This event is triggered after pre-relocation initialization of the 35 * driver model. Its parameter is NULL. 36 * A non-zero return code from the event handler let's the boot process 37 * fail. 38 */ 39 EVT_DM_POST_INIT_F, 40 41 /** 42 * @EVT_DM_POST_INIT_R: 43 * This event is triggered after post-relocation initialization of the 44 * driver model. Its parameter is NULL. 45 * A non-zero return code from the event handler let's the boot process 46 * fail. 47 */ 48 EVT_DM_POST_INIT_R, 49 50 /** 51 * @EVT_DM_PRE_PROBE: 52 * This event is triggered before probing a device. Its parameter is the 53 * device to be probed. 54 * A non-zero return code from the event handler lets the device not 55 * being probed. 56 */ 57 EVT_DM_PRE_PROBE, 58 59 /** 60 * @EVT_DM_POST_PROBE: 61 * This event is triggered after probing a device. Its parameter is the 62 * device that was probed. 63 * A non-zero return code from the event handler leaves the device in 64 * the unprobed state and therefore not usable. 65 */ 66 EVT_DM_POST_PROBE, 67 68 /** 69 * @EVT_DM_PRE_REMOVE: 70 * This event is triggered after removing a device. Its parameter is 71 * the device to be removed. 72 * A non-zero return code from the event handler stops the removal of 73 * the device before any changes. 74 */ 75 EVT_DM_PRE_REMOVE, 76 77 /** 78 * @EVT_DM_POST_REMOVE: 79 * This event is triggered before removing a device. Its parameter is 80 * the device that was removed. 81 * A non-zero return code stops from the event handler the removal of 82 * the device after all removal changes. The previous state is not 83 * restored. All children will be gone and the device may not be 84 * functional. 85 */ 86 EVT_DM_POST_REMOVE, 87 88 /** 89 * @EVT_MISC_INIT_F: 90 * This event is triggered during the initialization sequence before 91 * relocation. Its parameter is NULL. 92 * A non-zero return code from the event handler let's the boot process 93 * fail. 94 */ 95 EVT_MISC_INIT_F, 96 97 /** 98 * @EVT_FSP_INIT_F: 99 * This event is triggered before relocation to set up Firmware Support 100 * Package. 101 * Where U-Boot relies on binary blobs to handle part of the system 102 * init, this event can be used to set up the blobs. This is used on 103 * some Intel platforms 104 */ 105 EVT_FSP_INIT_F, 106 107 /** 108 * @EVT_SETTINGS_R: 109 * This event is triggered post-relocation and before console init. 110 * This gives an option to perform any platform-dependent setup, which 111 * needs to take place before show_board_info() (e.g. readout of EEPROM 112 * stored settings). 113 */ 114 EVT_SETTINGS_R, 115 116 /** 117 * @EVT_LAST_STAGE_INIT: 118 * This event is triggered just before jumping to the main loop. 119 * Some boards need to perform initialisation immediately before control 120 * is passed to the command-line interpreter (e.g. for init that depend 121 * on later phases in the init sequence). 122 * 123 * Some parts can be only initialized if all others (like Interrupts) 124 * are up and running (e.g. the PC-style ISA keyboard). 125 */ 126 EVT_LAST_STAGE_INIT, 127 128 /** 129 * @EVT_FPGA_LOAD: 130 * The FPGA load hook is called after loading an FPGA with a new binary. 131 * Its parameter is of type struct event_fpga_load and contains 132 * information about the loaded image. 133 */ 134 EVT_FPGA_LOAD, 135 136 /** 137 * @EVT_FT_FIXUP: 138 * This event is triggered during device-tree fix up after all 139 * other device-tree fixups have been executed. 140 * Its parameter is of type struct event_ft_fixup which contains 141 * the address of the device-tree to fix up and the list of images to be 142 * booted. 143 * A non-zero return code from the event handler let's booting the 144 * images fail. 145 */ 146 EVT_FT_FIXUP, 147 148 /** 149 * @EVT_MAIN_LOOP: 150 * This event is triggered immediately before calling main_loop() which 151 * is the entry point of the command line. Its parameter is NULL. 152 * A non-zero return value causes the boot to fail. 153 */ 154 EVT_MAIN_LOOP, 155 156 /** 157 * @EVT_COUNT: 158 * This constants holds the maximum event number + 1 and is used when 159 * looping over all event classes. 160 */ 161 EVT_COUNT 162}; 163 164union event_data { 165 /** 166 * struct event_data_test - test data 167 * 168 * @signal: A value to update the state with 169 */ 170 struct event_data_test { 171 int signal; 172 } test; 173 174 /** 175 * struct event_dm - driver model event 176 * 177 * @dev: Device this event relates to 178 */ 179 struct event_dm { 180 struct udevice *dev; 181 } dm; 182 183 /** 184 * struct event_fpga_load - fpga load event 185 * 186 * @buf: The buffer that was loaded into the fpga 187 * @bsize: The size of the buffer that was loaded into the fpga 188 * @result: Result of the load operation 189 */ 190 struct event_fpga_load { 191 const void *buf; 192 size_t bsize; 193 int result; 194 } fpga_load; 195 196 /** 197 * struct event_ft_fixup - FDT fixup before booting 198 * 199 * @tree: tree to update 200 * @images: images which are being booted 201 */ 202 struct event_ft_fixup { 203 oftree tree; 204 struct bootm_headers *images; 205 } ft_fixup; 206}; 207 208/** 209 * struct event - an event that can be sent and received 210 * 211 * @type: Event type 212 * @data: Data for this particular event 213 */ 214struct event { 215 enum event_t type; 216 union event_data data; 217}; 218 219/* Flags for event spy */ 220enum evspy_flags { 221 EVSPYF_SIMPLE = 1 << 0, 222}; 223 224/** Function type for event handlers */ 225typedef int (*event_handler_t)(void *ctx, struct event *event); 226 227/** Function type for simple event handlers */ 228typedef int (*event_handler_simple_t)(void); 229 230/** 231 * struct evspy_info - information about an event spy 232 * 233 * @func: Function to call when the event is activated (must be first) 234 * @type: Event type 235 * @flags: Flags for this spy 236 * @id: Event id string 237 */ 238struct evspy_info { 239 event_handler_t func; 240 u8 type; 241 u8 flags; 242#if CONFIG_IS_ENABLED(EVENT_DEBUG) 243 const char *id; 244#endif 245}; 246 247/** 248 * struct evspy_info_simple - information about an event spy 249 * 250 * THis is the 'simple' record, the only difference being the handler function 251 * 252 * @func: Function to call when the event is activated (must be first) 253 * @type: Event type 254 * @flags: Flags for this spy 255 * @id: Event id string 256 */ 257struct evspy_info_simple { 258 event_handler_simple_t func; 259 u8 type; 260 u8 flags; 261#if CONFIG_IS_ENABLED(EVENT_DEBUG) 262 const char *id; 263#endif 264}; 265 266/* Declare a new event spy */ 267#if CONFIG_IS_ENABLED(EVENT_DEBUG) 268#define _ESPY_REC(_type, _func) { _func, _type, 0, #_func, } 269#define _ESPY_REC_SIMPLE(_type, _func) { _func, _type, EVSPYF_SIMPLE, #_func, } 270#else 271#define _ESPY_REC(_type, _func) { _func, _type, } 272#define _ESPY_REC_SIMPLE(_type, _func) { _func, _type, EVSPYF_SIMPLE } 273#endif 274 275static inline const char *event_spy_id(struct evspy_info *spy) 276{ 277#if CONFIG_IS_ENABLED(EVENT_DEBUG) 278 return spy->id; 279#else 280 return "?"; 281#endif 282} 283 284/* 285 * It seems that LTO will drop list entries if it decides they are not used, 286 * although the conditions that cause this are unclear. 287 * 288 * The example found is the following: 289 * 290 * static int sandbox_misc_init_f(void *ctx, struct event *event) 291 * { 292 * return sandbox_early_getopt_check(); 293 * } 294 * EVENT_SPY_FULL(EVT_MISC_INIT_F, sandbox_misc_init_f); 295 * 296 * where EVENT_SPY_FULL uses ll_entry_declare() 297 * 298 * In this case, LTO decides to drop the sandbox_misc_init_f() function 299 * (which is fine) but then drops the linker-list entry too. This means 300 * that the code no longer works, in this case sandbox no-longer checks its 301 * command-line arguments properly. 302 * 303 * Without LTO, the KEEP() command in the .lds file is enough to keep the 304 * entry around. But with LTO it seems that the entry has already been 305 * dropped before the link script is considered. 306 * 307 * The only solution I can think of is to mark linker-list entries as 'used' 308 * using an attribute. This should be safe, since we don't actually want to drop 309 * any of these. However this does slightly limit LTO's optimisation choices. 310 * 311 * Another issue has come up, only with clang: using 'static' makes it throw 312 * away the linker-list entry sometimes, e.g. with the EVT_FT_FIXUP entry in 313 * vbe_simple.c - so for now, make it global. 314 */ 315#define EVENT_SPY_FULL(_type, _func) \ 316 __used ll_entry_declare(struct evspy_info, _type ## _3_ ## _func, \ 317 evspy_info) = _ESPY_REC(_type, _func) 318 319/* Simple spy with no function arguemnts */ 320#define EVENT_SPY_SIMPLE(_type, _func) \ 321 __used ll_entry_declare(struct evspy_info_simple, \ 322 _type ## _3_ ## _func, \ 323 evspy_info) = _ESPY_REC_SIMPLE(_type, _func) 324 325/** 326 * event_register - register a new spy 327 * 328 * @id: Spy ID 329 * @type: Event type to subscribe to 330 * @func: Function to call when the event is sent 331 * @ctx: Context to pass to the function 332 * @return 0 if OK, -ve on error 333 */ 334int event_register(const char *id, enum event_t type, event_handler_t func, 335 void *ctx); 336 337/** event_show_spy_list( - Show a list of event spies */ 338void event_show_spy_list(void); 339 340/** 341 * event_type_name() - Get the name of an event type 342 * 343 * @type: Type to check 344 * Return: Name of event, or "(unknown)" if not known 345 */ 346const char *event_type_name(enum event_t type); 347 348/** 349 * event_notify() - notify spies about an event 350 * 351 * It is possible to pass in union event_data here but that may not be 352 * convenient if the data is elsewhere, or is one of the members of the union. 353 * So this uses a void * for @data, with a separate @size. 354 * 355 * @type: Event type 356 * @data: Event data to be sent (e.g. union_event_data) 357 * @size: Size of data in bytes 358 * @return 0 if OK, -ve on error 359 */ 360int event_notify(enum event_t type, void *data, int size); 361 362#if CONFIG_IS_ENABLED(EVENT) 363/** 364 * event_notify_null() - notify spies about an event 365 * 366 * Data is NULL and the size is 0 367 * 368 * @type: Event type 369 * @return 0 if OK, -ve on error 370 */ 371int event_notify_null(enum event_t type); 372#else 373static inline int event_notify_null(enum event_t type) 374{ 375 return 0; 376} 377#endif 378 379#if CONFIG_IS_ENABLED(EVENT_DYNAMIC) 380/** 381 * event_uninit() - Clean up dynamic events 382 * 383 * This removes all dynamic event handlers 384 */ 385int event_uninit(void); 386 387/** 388 * event_uninit() - Set up dynamic events 389 * 390 * Init a list of dynamic event handlers, so that these can be added as 391 * needed 392 */ 393int event_init(void); 394#else 395static inline int event_uninit(void) 396{ 397 return 0; 398} 399 400static inline int event_init(void) 401{ 402 return 0; 403} 404#endif 405 406#endif 407