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 | // 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> */ #define LOG_CATEGORY LOGC_EVENT #include <event.h> #include <event_internal.h> #include <log.h> #include <linker_lists.h> #include <malloc.h> #include <asm/global_data.h> #include <linux/errno.h> #include <linux/list.h> #include <relocate.h> DECLARE_GLOBAL_DATA_PTR; #if CONFIG_IS_ENABLED(EVENT_DEBUG) const char *const type_name[] = { "none", "test", /* Events related to driver model */ "dm_post_init_f", "dm_post_init_r", "dm_pre_probe", "dm_post_probe", "dm_pre_remove", "dm_post_remove", /* init hooks */ "misc_init_f", "fsp_init_r", "reserve_board", "settings_r", "last_stage_init", /* Fpga load hook */ "fpga_load", /* fdt hooks */ "ft_fixup_f", "ft_fixup", /* main loop events */ "main_loop", "bootcmd", /* booting */ "boot_os_addr", "bootm_final", }; _Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size"); #endif const char *event_type_name(enum event_t type) { #if CONFIG_IS_ENABLED(EVENT_DEBUG) if (type < ARRAY_SIZE(type_name)) return type_name[type]; else return "(unknown)"; #else return "(unknown)"; #endif } static int notify_static(struct event *ev) { struct evspy_info *start = ll_entry_start(struct evspy_info, evspy_info); const int n_ents = ll_entry_count(struct evspy_info, evspy_info); struct evspy_info *spy; for (spy = start; spy != start + n_ents; spy++) { if (spy->type == ev->type) { int ret; log_debug("Sending event %x/%s to spy '%s'\n", ev->type, event_type_name(ev->type), event_spy_id(spy)); if (spy->flags & EVSPYF_SIMPLE) { const struct evspy_info_simple *simple; simple = (struct evspy_info_simple *)spy; ret = simple->func(); } else { ret = spy->func(NULL, ev); } /* * TODO: Handle various return codes to * * - claim an event (no others will see it) * - return an error from the event */ if (ret) return log_msg_ret("spy", ret); } } return 0; } static int notify_dynamic(struct event *ev) { struct event_state *state = gd_event_state(); struct event_spy *spy, *next; list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node) { if (spy->type == ev->type) { int ret; log_debug("Sending event %x/%s to spy '%s'\n", ev->type, event_type_name(ev->type), spy->id); ret = spy->func(spy->ctx, ev); /* * TODO: Handle various return codes to * * - claim an event (no others will see it) * - return an error from the event */ if (ret) return log_msg_ret("spy", ret); } } return 0; } static int event_notify_internal(struct event *event, const void *data, int size) { int ret; if (size > sizeof(event->data)) return log_msg_ret("size", -E2BIG); if (data && size) memcpy(&event->data, data, size); ret = notify_static(event); if (ret) return log_msg_ret("sta", ret); if (CONFIG_IS_ENABLED(EVENT_DYNAMIC)) { ret = notify_dynamic(event); if (ret) return log_msg_ret("dyn", ret); } return 0; } int event_notify(enum event_t type, const void *data, int size) { struct event event; event.type = type; return event_notify_internal(&event, data, size); } int event_notify_resp(enum event_t type, void *data, int size) { struct event event; int ret; event.type = type; ret = event_notify_internal(&event, data, size); /* Copy potentially modified event data back to caller */ if (data && size) memcpy(data, &event.data, size); return ret; } int event_notify_null(enum event_t type) { return event_notify(type, NULL, 0); } void event_show_spy_list(void) { struct evspy_info *start = ll_entry_start(struct evspy_info, evspy_info); const int n_ents = ll_entry_count(struct evspy_info, evspy_info); struct evspy_info *spy; const int size = sizeof(ulong) * 2; printf("Seq %-24s %*s %s\n", "Type", size, "Function", "ID"); for (spy = start; spy != start + n_ents; spy++) { printf("%3x %-3x %-20s %*p %s\n", (uint)(spy - start), spy->type, event_type_name(spy->type), size, spy->func, event_spy_id(spy)); } } #if CONFIG_IS_ENABLED(EVENT_DYNAMIC) static void spy_free(struct event_spy *spy) { list_del(&spy->sibling_node); } int event_register(const char *id, enum event_t type, event_handler_t func, void *ctx) { struct event_state *state = gd_event_state(); struct event_spy *spy; spy = malloc(sizeof(*spy)); if (!spy) return log_msg_ret("alloc", -ENOMEM); spy->id = id; spy->type = type; spy->func = func; spy->ctx = ctx; list_add_tail(&spy->sibling_node, &state->spy_head); return 0; } int event_uninit(void) { struct event_state *state = gd_event_state(); struct event_spy *spy, *next; list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node) spy_free(spy); return 0; } int event_init(void) { struct event_state *state = gd_event_state(); INIT_LIST_HEAD(&state->spy_head); return 0; } #endif /* EVENT_DYNAMIC */ |