Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 | /* SPDX-License-Identifier: GPL-2.0+ */ /* * Events provide a general-purpose way to react to / subscribe to changes * within U-Boot * * Copyright 2021 Google LLC * Written by Simon Glass <sjg@chromium.org> */ #ifndef __event_h #define __event_h #include <dm/ofnode_decl.h> #include <linux/types.h> /** * enum event_t - Types of events supported by U-Boot * * @EVT_DM_PRE_PROBE: Device is about to be probed */ enum event_t { /** * @EVT_NONE: This zero value is not used for events. */ EVT_NONE = 0, /** * @EVT_TEST: This event is used in unit tests. */ EVT_TEST, /** * @EVT_DM_POST_INIT_F: * This event is triggered after pre-relocation initialization of the * driver model. Its parameter is NULL. * A non-zero return code from the event handler let's the boot process * fail. */ EVT_DM_POST_INIT_F, /** * @EVT_DM_POST_INIT_R: * This event is triggered after post-relocation initialization of the * driver model. Its parameter is NULL. * A non-zero return code from the event handler let's the boot process * fail. */ EVT_DM_POST_INIT_R, /** * @EVT_DM_PRE_PROBE: * This event is triggered before probing a device. Its parameter is the * device to be probed. * A non-zero return code from the event handler lets the device not * being probed. */ EVT_DM_PRE_PROBE, /** * @EVT_DM_POST_PROBE: * This event is triggered after probing a device. Its parameter is the * device that was probed. * A non-zero return code from the event handler leaves the device in * the unprobed state and therefore not usable. */ EVT_DM_POST_PROBE, /** * @EVT_DM_PRE_REMOVE: * This event is triggered after removing a device. Its parameter is * the device to be removed. * A non-zero return code from the event handler stops the removal of * the device before any changes. */ EVT_DM_PRE_REMOVE, /** * @EVT_DM_POST_REMOVE: * This event is triggered before removing a device. Its parameter is * the device that was removed. * A non-zero return code stops from the event handler the removal of * the device after all removal changes. The previous state is not * restored. All children will be gone and the device may not be * functional. */ EVT_DM_POST_REMOVE, /** * @EVT_MISC_INIT_F: * This event is triggered during the initialization sequence before * relocation. Its parameter is NULL. * A non-zero return code from the event handler let's the boot process * fail. */ EVT_MISC_INIT_F, /** * @EVT_FPGA_LOAD: * The FPGA load hook is called after loading an FPGA with a new binary. * Its parameter is of type struct event_fpga_load and contains * information about the loaded image. */ EVT_FPGA_LOAD, /** * @EVT_FT_FIXUP: * This event is triggered during device-tree fix up after all * other device-tree fixups have been executed. * Its parameter is of type struct event_ft_fixup which contains * the address of the device-tree to fix up and the list of images to be * booted. * A non-zero return code from the event handler let's booting the * images fail. */ EVT_FT_FIXUP, /** * @EVT_MAIN_LOOP: * This event is triggered immediately before calling main_loop() which * is the entry point of the command line. Its parameter is NULL. * A non-zero return value causes the boot to fail. */ EVT_MAIN_LOOP, /** * @EVT_COUNT: * This constants holds the maximum event number + 1 and is used when * looping over all event classes. */ EVT_COUNT }; union event_data { /** * struct event_data_test - test data * * @signal: A value to update the state with */ struct event_data_test { int signal; } test; /** * struct event_dm - driver model event * * @dev: Device this event relates to */ struct event_dm { struct udevice *dev; } dm; /** * struct event_fpga_load - fpga load event * * @buf: The buffer that was loaded into the fpga * @bsize: The size of the buffer that was loaded into the fpga * @result: Result of the load operation */ struct event_fpga_load { const void *buf; size_t bsize; int result; } fpga_load; /** * struct event_ft_fixup - FDT fixup before booting * * @tree: tree to update * @images: images which are being booted */ struct event_ft_fixup { oftree tree; struct bootm_headers *images; } ft_fixup; }; /** * struct event - an event that can be sent and received * * @type: Event type * @data: Data for this particular event */ struct event { enum event_t type; union event_data data; }; /** Function type for event handlers */ typedef int (*event_handler_t)(void *ctx, struct event *event); /** * struct evspy_info - information about an event spy * * @func: Function to call when the event is activated (must be first) * @type: Event type * @id: Event id string */ struct evspy_info { event_handler_t func; enum event_t type; #if CONFIG_IS_ENABLED(EVENT_DEBUG) const char *id; #endif }; /* Declare a new event spy */ #if CONFIG_IS_ENABLED(EVENT_DEBUG) #define _ESPY_REC(_type, _func) { _func, _type, #_func, } #else #define _ESPY_REC(_type, _func) { _func, _type, } #endif static inline const char *event_spy_id(struct evspy_info *spy) { #if CONFIG_IS_ENABLED(EVENT_DEBUG) return spy->id; #else return "?"; #endif } /* * It seems that LTO will drop list entries if it decides they are not used, * although the conditions that cause this are unclear. * * The example found is the following: * * static int sandbox_misc_init_f(void *ctx, struct event *event) * { * return sandbox_early_getopt_check(); * } * EVENT_SPY(EVT_MISC_INIT_F, sandbox_misc_init_f); * * where EVENT_SPY uses ll_entry_declare() * * In this case, LTO decides to drop the sandbox_misc_init_f() function * (which is fine) but then drops the linker-list entry too. This means * that the code no longer works, in this case sandbox no-longer checks its * command-line arguments properly. * * Without LTO, the KEEP() command in the .lds file is enough to keep the * entry around. But with LTO it seems that the entry has already been * dropped before the link script is considered. * * The only solution I can think of is to mark linker-list entries as 'used' * using an attribute. This should be safe, since we don't actually want to drop * any of these. However this does slightly limit LTO's optimisation choices. * * Another issue has come up, only with clang: using 'static' makes it throw * away the linker-list entry sometimes, e.g. with the EVT_FT_FIXUP entry in * vbe_simple.c - so for now, make it global. */ #define EVENT_SPY(_type, _func) \ __used ll_entry_declare(struct evspy_info, _type ## _3_ ## _func, \ evspy_info) = _ESPY_REC(_type, _func) /** * event_register - register a new spy * * @id: Spy ID * @type: Event type to subscribe to * @func: Function to call when the event is sent * @ctx: Context to pass to the function * @return 0 if OK, -ve on error */ int event_register(const char *id, enum event_t type, event_handler_t func, void *ctx); /** event_show_spy_list( - Show a list of event spies */ void event_show_spy_list(void); /** * event_manual_reloc() - Relocate event handler pointers * * Relocate event handler pointers for all static event spies. It is called * during the generic board init sequence, after relocation. * * Return: 0 if OK */ int event_manual_reloc(void); /** * event_notify() - notify spies about an event * * It is possible to pass in union event_data here but that may not be * convenient if the data is elsewhere, or is one of the members of the union. * So this uses a void * for @data, with a separate @size. * * @type: Event type * @data: Event data to be sent (e.g. union_event_data) * @size: Size of data in bytes * @return 0 if OK, -ve on error */ int event_notify(enum event_t type, void *data, int size); #if CONFIG_IS_ENABLED(EVENT) /** * event_notify_null() - notify spies about an event * * Data is NULL and the size is 0 * * @type: Event type * @return 0 if OK, -ve on error */ int event_notify_null(enum event_t type); #else static inline int event_notify_null(enum event_t type) { return 0; } #endif #if CONFIG_IS_ENABLED(EVENT_DYNAMIC) /** * event_uninit() - Clean up dynamic events * * This removes all dynamic event handlers */ int event_uninit(void); /** * event_uninit() - Set up dynamic events * * Init a list of dynamic event handlers, so that these can be added as * needed */ int event_init(void); #else static inline int event_uninit(void) { return 0; } static inline int event_init(void) { return 0; } #endif #endif |