blob: 8a61908888454c4b32b5141bcf817c3934ca93e2 [file] [log] [blame]
Simon Glass87a5d1b2022-03-04 08:43:00 -07001// 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>
Ovidiu Panaitcebc8162022-05-15 21:40:29 +030020#include <relocate.h>
Simon Glass87a5d1b2022-03-04 08:43:00 -070021
22DECLARE_GLOBAL_DATA_PTR;
23
24#if CONFIG_IS_ENABLED(EVENT_DEBUG)
25const char *const type_name[] = {
26 "none",
27 "test",
Simon Glass5b896ed2022-03-04 08:43:03 -070028
29 /* Events related to driver model */
Jaehoon Chungb4966202023-08-01 19:17:00 +090030 "dm_post_init_f",
Simon Glass5b896ed2022-03-04 08:43:03 -070031 "dm_pre_probe",
32 "dm_post_probe",
33 "dm_pre_remove",
34 "dm_post_remove",
Simon Glass42fdceb2022-03-04 08:43:04 -070035
36 /* init hooks */
37 "misc_init_f",
Simon Glass13a7db92023-08-21 21:16:59 -060038 "fsp_init_r",
Simon Glass98887ab2022-07-30 15:52:31 -060039
Christian Taedckea1190b42023-07-20 09:27:24 +020040 /* Fpga load hook */
41 "fpga_load",
42
Simon Glass98887ab2022-07-30 15:52:31 -060043 /* fdt hooks */
44 "ft_fixup",
Sughosh Ganu467bad52022-10-21 18:16:01 +053045
46 /* main loop events */
47 "main_loop",
Simon Glass87a5d1b2022-03-04 08:43:00 -070048};
49
50_Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
51#endif
52
Simon Glassfb7dfca2023-08-21 21:16:53 -060053const char *event_type_name(enum event_t type)
Simon Glass87a5d1b2022-03-04 08:43:00 -070054{
55#if CONFIG_IS_ENABLED(EVENT_DEBUG)
56 return type_name[type];
57#else
58 return "(unknown)";
59#endif
60}
61
62static int notify_static(struct event *ev)
63{
64 struct evspy_info *start =
65 ll_entry_start(struct evspy_info, evspy_info);
66 const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
67 struct evspy_info *spy;
68
69 for (spy = start; spy != start + n_ents; spy++) {
70 if (spy->type == ev->type) {
71 int ret;
72
73 log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
74 event_type_name(ev->type), event_spy_id(spy));
Simon Glassba5e3e12023-08-21 21:16:48 -060075 if (spy->flags & EVSPYF_SIMPLE) {
76 const struct evspy_info_simple *simple;
77
78 simple = (struct evspy_info_simple *)spy;
79 ret = simple->func();
80 } else {
81 ret = spy->func(NULL, ev);
82 }
Simon Glass87a5d1b2022-03-04 08:43:00 -070083
84 /*
85 * TODO: Handle various return codes to
86 *
87 * - claim an event (no others will see it)
88 * - return an error from the event
89 */
90 if (ret)
91 return log_msg_ret("spy", ret);
92 }
93 }
94
95 return 0;
96}
97
98static int notify_dynamic(struct event *ev)
99{
100 struct event_state *state = gd_event_state();
101 struct event_spy *spy, *next;
102
103 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node) {
104 if (spy->type == ev->type) {
105 int ret;
106
107 log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
108 event_type_name(ev->type), spy->id);
109 ret = spy->func(spy->ctx, ev);
110
111 /*
112 * TODO: Handle various return codes to
113 *
114 * - claim an event (no others will see it)
115 * - return an error from the event
116 */
117 if (ret)
118 return log_msg_ret("spy", ret);
119 }
120 }
121
122 return 0;
123}
124
125int event_notify(enum event_t type, void *data, int size)
126{
127 struct event event;
128 int ret;
129
130 event.type = type;
131 if (size > sizeof(event.data))
132 return log_msg_ret("size", -E2BIG);
133 memcpy(&event.data, data, size);
134
135 ret = notify_static(&event);
136 if (ret)
Simon Glass19efd432023-01-17 10:47:31 -0700137 return log_msg_ret("sta", ret);
Simon Glass87a5d1b2022-03-04 08:43:00 -0700138
139 if (CONFIG_IS_ENABLED(EVENT_DYNAMIC)) {
140 ret = notify_dynamic(&event);
141 if (ret)
142 return log_msg_ret("dyn", ret);
143 }
144
145 return 0;
146}
147
148int event_notify_null(enum event_t type)
149{
150 return event_notify(type, NULL, 0);
151}
152
153void event_show_spy_list(void)
154{
155 struct evspy_info *start =
156 ll_entry_start(struct evspy_info, evspy_info);
157 const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
158 struct evspy_info *spy;
159 const int size = sizeof(ulong) * 2;
160
161 printf("Seq %-24s %*s %s\n", "Type", size, "Function", "ID");
162 for (spy = start; spy != start + n_ents; spy++) {
163 printf("%3x %-3x %-20s %*p %s\n", (uint)(spy - start),
164 spy->type, event_type_name(spy->type), size, spy->func,
165 event_spy_id(spy));
166 }
167}
168
Simon Glass00ba40f2023-02-05 15:40:19 -0700169#if IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)
Ovidiu Panaitcebc8162022-05-15 21:40:29 +0300170int event_manual_reloc(void)
171{
172 struct evspy_info *spy, *end;
173
174 spy = ll_entry_start(struct evspy_info, evspy_info);
175 end = ll_entry_end(struct evspy_info, evspy_info);
176 for (; spy < end; spy++)
177 MANUAL_RELOC(spy->func);
178
179 return 0;
180}
181#endif
182
Simon Glass87a5d1b2022-03-04 08:43:00 -0700183#if CONFIG_IS_ENABLED(EVENT_DYNAMIC)
184static void spy_free(struct event_spy *spy)
185{
186 list_del(&spy->sibling_node);
187}
188
189int event_register(const char *id, enum event_t type, event_handler_t func, void *ctx)
190{
191 struct event_state *state = gd_event_state();
192 struct event_spy *spy;
193
Simon Glass87a5d1b2022-03-04 08:43:00 -0700194 spy = malloc(sizeof(*spy));
195 if (!spy)
196 return log_msg_ret("alloc", -ENOMEM);
197
198 spy->id = id;
199 spy->type = type;
200 spy->func = func;
201 spy->ctx = ctx;
202 list_add_tail(&spy->sibling_node, &state->spy_head);
203
204 return 0;
205}
206
207int event_uninit(void)
208{
209 struct event_state *state = gd_event_state();
210 struct event_spy *spy, *next;
211
212 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node)
213 spy_free(spy);
214
215 return 0;
216}
217
218int event_init(void)
219{
220 struct event_state *state = gd_event_state();
221
222 INIT_LIST_HEAD(&state->spy_head);
223
224 return 0;
225}
226#endif /* EVENT_DYNAMIC */