Simon Glass | abe5d11 | 2022-03-04 08:43:08 -0700 | [diff] [blame] | 1 | .. SPDX-License-Identifier: GPL-2.0+ |
| 2 | |
| 3 | Events |
| 4 | ====== |
| 5 | |
| 6 | U-Boot supports a way for various events to be handled by interested |
| 7 | subsystems. This provide a generic way to handle 'hooks' like setting up the |
| 8 | CPUs after driver model is active, or reading a partition table after a new |
| 9 | block device is probed. |
| 10 | |
| 11 | Rather than using weak functions and direct calls across subsystemss, it is |
| 12 | often easier to use an event. |
| 13 | |
Simon Glass | 55171ae | 2023-05-04 16:50:45 -0600 | [diff] [blame] | 14 | An event consists of a type (e.g. EVT_DM_POST_INIT_F) and some optional data, |
Hugo Villeneuve | ed356ac | 2023-04-25 09:46:45 -0400 | [diff] [blame] | 15 | in `union event_data`. An event spy can be created to watch for events of a |
Simon Glass | abe5d11 | 2022-03-04 08:43:08 -0700 | [diff] [blame] | 16 | particular type. When the event is created, it is sent to each spy in turn. |
| 17 | |
| 18 | |
| 19 | Declaring a spy |
| 20 | --------------- |
| 21 | |
| 22 | To declare a spy, use something like this:: |
| 23 | |
Simon Glass | 12be60d | 2023-08-21 21:16:58 -0600 | [diff] [blame] | 24 | static int snow_check_temperature(void) |
Simon Glass | abe5d11 | 2022-03-04 08:43:08 -0700 | [diff] [blame] | 25 | { |
| 26 | /* do something */ |
| 27 | return 0; |
| 28 | } |
Simon Glass | 12be60d | 2023-08-21 21:16:58 -0600 | [diff] [blame] | 29 | EVENT_SPY_SIMPLE(EVT_DM_POST_INIT_F, snow_check_temperature); |
Simon Glass | abe5d11 | 2022-03-04 08:43:08 -0700 | [diff] [blame] | 30 | |
Bin Meng | 268d25f | 2023-06-12 14:12:13 +0800 | [diff] [blame] | 31 | This function is called when EVT_DM_POST_INIT_F is emitted, i.e. after the |
| 32 | driver model is initialized (in U-Boot proper before and after relocation). |
Simon Glass | abe5d11 | 2022-03-04 08:43:08 -0700 | [diff] [blame] | 33 | |
Simon Glass | 12be60d | 2023-08-21 21:16:58 -0600 | [diff] [blame] | 34 | If you need access to the event data, use `EVENT_SPY_FULL`, like this:: |
| 35 | |
| 36 | static int snow_setup_cpus(void *ctx, struct event *event) |
| 37 | { |
| 38 | /* do something that uses event->data*/ |
| 39 | return 0; |
| 40 | } |
| 41 | EVENT_SPY_FULL(EVT_DM_POST_INIT_F, snow_setup_cpus); |
| 42 | |
| 43 | Note that the context is always NULL for a static spy. See below for information |
| 44 | about how to use a dynamic spy. |
| 45 | |
| 46 | The return value is handled by the event emitter. If non-zero, then the error |
| 47 | is returned to the function which emitted the event, i.e. the one that called |
| 48 | `event_notify()`. |
Simon Glass | abe5d11 | 2022-03-04 08:43:08 -0700 | [diff] [blame] | 49 | |
| 50 | Debugging |
| 51 | --------- |
| 52 | |
| 53 | To assist with debugging events, enable `CONFIG_EVENT_DEBUG` and |
Tom Rini | 01f1ab6 | 2022-04-04 10:45:33 -0400 | [diff] [blame] | 54 | `CONFIG_CMD_EVENT`. The :doc:`../usage/cmd/event` command can then be used to |
Simon Glass | abe5d11 | 2022-03-04 08:43:08 -0700 | [diff] [blame] | 55 | provide a spy list. |
| 56 | |
| 57 | It is also possible to list spy information from the U-Boot executable,, using |
| 58 | the `event_dump.py` script:: |
| 59 | |
| 60 | $ scripts/event_dump.py /tmp/b/sandbox/u-boot |
| 61 | Event type Id Source location |
| 62 | -------------------- ------------------------------ ------------------------------ |
| 63 | EVT_MISC_INIT_F f:sandbox_misc_init_f arch/sandbox/cpu/start.c:125 |
| 64 | |
| 65 | This shows each event spy in U-Boot, along with the event type, function name |
| 66 | (or ID) and source location. |
| 67 | |
| 68 | Note that if `CONFIG_EVENT_DEBUG` is not enabled, the event ID is missing, so |
| 69 | the function is shown instead (with an `f:` prefix as above). Since the ID is |
| 70 | generally the same as the function name, this does not matter much. |
| 71 | |
| 72 | The event type is decoded by the symbol used by U-Boot for the event linker |
| 73 | list. Symbols have the form:: |
| 74 | |
| 75 | _u_boot_list_2_evspy_info_2_EVT_MISC_INIT_F |
| 76 | |
| 77 | so the event type can be read from the end. To manually list spy information |
| 78 | in an image, use $(CROSS_COMPILE)nm:: |
| 79 | |
| 80 | nm u-boot |grep evspy |grep list |
| 81 | 00000000002d6300 D _u_boot_list_2_evspy_info_2_EVT_MISC_INIT_F |
Simon Glass | d67811a | 2023-01-20 14:46:05 -0700 | [diff] [blame] | 82 | |
| 83 | Logging is also available. Events use category `LOGC_EVENT`, so you can enable |
| 84 | logging on that, or add `#define LOG_DEBUG` to the top of `common/event.c` to |
| 85 | see events being sent. |
| 86 | |
| 87 | |
| 88 | Dynamic events |
| 89 | -------------- |
| 90 | |
| 91 | Static events provide a way of dealing with events known at build time. In some |
| 92 | cases we want to attach an event handler at runtime. For example, we may wish |
| 93 | to be notified when a particular device is probed or removed. |
| 94 | |
| 95 | This can be handled by enabling `CONFIG_EVENT_DYNAMIC`. It is then possible to |
| 96 | call `event_register()` to register a new handler for a particular event. |
| 97 | |
Simon Glass | 12be60d | 2023-08-21 21:16:58 -0600 | [diff] [blame] | 98 | If some context is need for the spy, you can pass a pointer to |
| 99 | `event_register()` to provide that. Note that the context is only passed to |
| 100 | a spy registered with `EVENT_SPY_FULL`. |
| 101 | |
Simon Glass | d67811a | 2023-01-20 14:46:05 -0700 | [diff] [blame] | 102 | Dynamic event handlers are called after all the static event spy handlers have |
| 103 | been processed. Of course, since dynamic event handlers are created at runtime |
| 104 | it is not possible to use the `event_dump.py` to see them. |
| 105 | |
| 106 | At present there is no way to list dynamic event handlers from the command line, |
| 107 | nor to deregister a dynamic event handler. These features can be added when |
| 108 | needed. |