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#define LOG_CATEGORY LOGC_EVENT 11 12#include <common.h> 13#include <event.h> 14#include <event_internal.h> 15#include <log.h> 16#include <linker_lists.h> 17#include <malloc.h> 18#include <asm/global_data.h> 19#include <linux/list.h> 20#include <relocate.h> 21 22DECLARE_GLOBAL_DATA_PTR; 23 24#if CONFIG_IS_ENABLED(EVENT_DEBUG) 25const char *const type_name[] = { 26 "none", 27 "test", 28 29 /* Events related to driver model */ 30 "dm_post_init_f", 31 "dm_post_init_r", 32 "dm_pre_probe", 33 "dm_post_probe", 34 "dm_pre_remove", 35 "dm_post_remove", 36 37 /* init hooks */ 38 "misc_init_f", 39 "fsp_init_r", 40 "settings_r", 41 "last_stage_init", 42 43 /* Fpga load hook */ 44 "fpga_load", 45 46 /* fdt hooks */ 47 "ft_fixup", 48 49 /* main loop events */ 50 "main_loop", 51}; 52 53_Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size"); 54#endif 55 56const char *event_type_name(enum event_t type) 57{ 58#if CONFIG_IS_ENABLED(EVENT_DEBUG) 59 if (type < ARRAY_SIZE(type_name)) 60 return type_name[type]; 61 else 62 return "(unknown)"; 63#else 64 return "(unknown)"; 65#endif 66} 67 68static int notify_static(struct event *ev) 69{ 70 struct evspy_info *start = 71 ll_entry_start(struct evspy_info, evspy_info); 72 const int n_ents = ll_entry_count(struct evspy_info, evspy_info); 73 struct evspy_info *spy; 74 75 for (spy = start; spy != start + n_ents; spy++) { 76 if (spy->type == ev->type) { 77 int ret; 78 79 log_debug("Sending event %x/%s to spy '%s'\n", ev->type, 80 event_type_name(ev->type), event_spy_id(spy)); 81 if (spy->flags & EVSPYF_SIMPLE) { 82 const struct evspy_info_simple *simple; 83 84 simple = (struct evspy_info_simple *)spy; 85 ret = simple->func(); 86 } else { 87 ret = spy->func(NULL, ev); 88 } 89 90 /* 91 * TODO: Handle various return codes to 92 * 93 * - claim an event (no others will see it) 94 * - return an error from the event 95 */ 96 if (ret) 97 return log_msg_ret("spy", ret); 98 } 99 } 100 101 return 0; 102} 103 104static int notify_dynamic(struct event *ev) 105{ 106 struct event_state *state = gd_event_state(); 107 struct event_spy *spy, *next; 108 109 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node) { 110 if (spy->type == ev->type) { 111 int ret; 112 113 log_debug("Sending event %x/%s to spy '%s'\n", ev->type, 114 event_type_name(ev->type), spy->id); 115 ret = spy->func(spy->ctx, ev); 116 117 /* 118 * TODO: Handle various return codes to 119 * 120 * - claim an event (no others will see it) 121 * - return an error from the event 122 */ 123 if (ret) 124 return log_msg_ret("spy", ret); 125 } 126 } 127 128 return 0; 129} 130 131int event_notify(enum event_t type, void *data, int size) 132{ 133 struct event event; 134 int ret; 135 136 event.type = type; 137 if (size > sizeof(event.data)) 138 return log_msg_ret("size", -E2BIG); 139 memcpy(&event.data, data, size); 140 141 ret = notify_static(&event); 142 if (ret) 143 return log_msg_ret("sta", ret); 144 145 if (CONFIG_IS_ENABLED(EVENT_DYNAMIC)) { 146 ret = notify_dynamic(&event); 147 if (ret) 148 return log_msg_ret("dyn", ret); 149 } 150 151 return 0; 152} 153 154int event_notify_null(enum event_t type) 155{ 156 return event_notify(type, NULL, 0); 157} 158 159void event_show_spy_list(void) 160{ 161 struct evspy_info *start = 162 ll_entry_start(struct evspy_info, evspy_info); 163 const int n_ents = ll_entry_count(struct evspy_info, evspy_info); 164 struct evspy_info *spy; 165 const int size = sizeof(ulong) * 2; 166 167 printf("Seq %-24s %*s %s\n", "Type", size, "Function", "ID"); 168 for (spy = start; spy != start + n_ents; spy++) { 169 printf("%3x %-3x %-20s %*p %s\n", (uint)(spy - start), 170 spy->type, event_type_name(spy->type), size, spy->func, 171 event_spy_id(spy)); 172 } 173} 174 175#if CONFIG_IS_ENABLED(EVENT_DYNAMIC) 176static void spy_free(struct event_spy *spy) 177{ 178 list_del(&spy->sibling_node); 179} 180 181int event_register(const char *id, enum event_t type, event_handler_t func, void *ctx) 182{ 183 struct event_state *state = gd_event_state(); 184 struct event_spy *spy; 185 186 spy = malloc(sizeof(*spy)); 187 if (!spy) 188 return log_msg_ret("alloc", -ENOMEM); 189 190 spy->id = id; 191 spy->type = type; 192 spy->func = func; 193 spy->ctx = ctx; 194 list_add_tail(&spy->sibling_node, &state->spy_head); 195 196 return 0; 197} 198 199int event_uninit(void) 200{ 201 struct event_state *state = gd_event_state(); 202 struct event_spy *spy, *next; 203 204 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node) 205 spy_free(spy); 206 207 return 0; 208} 209 210int event_init(void) 211{ 212 struct event_state *state = gd_event_state(); 213 214 INIT_LIST_HEAD(&state->spy_head); 215 216 return 0; 217} 218#endif /* EVENT_DYNAMIC */ 219