blob: 4845104b17dc69271fbf89bfe05dda6f4853cd51 [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 Glass91caa3b2023-08-21 21:17:01 -060039 "last_stage_init",
Simon Glass98887ab2022-07-30 15:52:31 -060040
Christian Taedckea1190b42023-07-20 09:27:24 +020041 /* Fpga load hook */
42 "fpga_load",
43
Simon Glass98887ab2022-07-30 15:52:31 -060044 /* fdt hooks */
45 "ft_fixup",
Sughosh Ganu467bad52022-10-21 18:16:01 +053046
47 /* main loop events */
48 "main_loop",
Simon Glass87a5d1b2022-03-04 08:43:00 -070049};
50
51_Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
52#endif
53
Simon Glassfb7dfca2023-08-21 21:16:53 -060054const char *event_type_name(enum event_t type)
Simon Glass87a5d1b2022-03-04 08:43:00 -070055{
56#if CONFIG_IS_ENABLED(EVENT_DEBUG)
57 return type_name[type];
58#else
59 return "(unknown)";
60#endif
61}
62
63static int notify_static(struct event *ev)
64{
65 struct evspy_info *start =
66 ll_entry_start(struct evspy_info, evspy_info);
67 const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
68 struct evspy_info *spy;
69
70 for (spy = start; spy != start + n_ents; spy++) {
71 if (spy->type == ev->type) {
72 int ret;
73
74 log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
75 event_type_name(ev->type), event_spy_id(spy));
Simon Glassba5e3e12023-08-21 21:16:48 -060076 if (spy->flags & EVSPYF_SIMPLE) {
77 const struct evspy_info_simple *simple;
78
79 simple = (struct evspy_info_simple *)spy;
80 ret = simple->func();
81 } else {
82 ret = spy->func(NULL, ev);
83 }
Simon Glass87a5d1b2022-03-04 08:43:00 -070084
85 /*
86 * TODO: Handle various return codes to
87 *
88 * - claim an event (no others will see it)
89 * - return an error from the event
90 */
91 if (ret)
92 return log_msg_ret("spy", ret);
93 }
94 }
95
96 return 0;
97}
98
99static int notify_dynamic(struct event *ev)
100{
101 struct event_state *state = gd_event_state();
102 struct event_spy *spy, *next;
103
104 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node) {
105 if (spy->type == ev->type) {
106 int ret;
107
108 log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
109 event_type_name(ev->type), spy->id);
110 ret = spy->func(spy->ctx, ev);
111
112 /*
113 * TODO: Handle various return codes to
114 *
115 * - claim an event (no others will see it)
116 * - return an error from the event
117 */
118 if (ret)
119 return log_msg_ret("spy", ret);
120 }
121 }
122
123 return 0;
124}
125
126int event_notify(enum event_t type, void *data, int size)
127{
128 struct event event;
129 int ret;
130
131 event.type = type;
132 if (size > sizeof(event.data))
133 return log_msg_ret("size", -E2BIG);
134 memcpy(&event.data, data, size);
135
136 ret = notify_static(&event);
137 if (ret)
Simon Glass19efd432023-01-17 10:47:31 -0700138 return log_msg_ret("sta", ret);
Simon Glass87a5d1b2022-03-04 08:43:00 -0700139
140 if (CONFIG_IS_ENABLED(EVENT_DYNAMIC)) {
141 ret = notify_dynamic(&event);
142 if (ret)
143 return log_msg_ret("dyn", ret);
144 }
145
146 return 0;
147}
148
149int event_notify_null(enum event_t type)
150{
151 return event_notify(type, NULL, 0);
152}
153
154void event_show_spy_list(void)
155{
156 struct evspy_info *start =
157 ll_entry_start(struct evspy_info, evspy_info);
158 const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
159 struct evspy_info *spy;
160 const int size = sizeof(ulong) * 2;
161
162 printf("Seq %-24s %*s %s\n", "Type", size, "Function", "ID");
163 for (spy = start; spy != start + n_ents; spy++) {
164 printf("%3x %-3x %-20s %*p %s\n", (uint)(spy - start),
165 spy->type, event_type_name(spy->type), size, spy->func,
166 event_spy_id(spy));
167 }
168}
169
Simon Glass00ba40f2023-02-05 15:40:19 -0700170#if IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)
Ovidiu Panaitcebc8162022-05-15 21:40:29 +0300171int event_manual_reloc(void)
172{
173 struct evspy_info *spy, *end;
174
175 spy = ll_entry_start(struct evspy_info, evspy_info);
176 end = ll_entry_end(struct evspy_info, evspy_info);
177 for (; spy < end; spy++)
178 MANUAL_RELOC(spy->func);
179
180 return 0;
181}
182#endif
183
Simon Glass87a5d1b2022-03-04 08:43:00 -0700184#if CONFIG_IS_ENABLED(EVENT_DYNAMIC)
185static void spy_free(struct event_spy *spy)
186{
187 list_del(&spy->sibling_node);
188}
189
190int event_register(const char *id, enum event_t type, event_handler_t func, void *ctx)
191{
192 struct event_state *state = gd_event_state();
193 struct event_spy *spy;
194
Simon Glass87a5d1b2022-03-04 08:43:00 -0700195 spy = malloc(sizeof(*spy));
196 if (!spy)
197 return log_msg_ret("alloc", -ENOMEM);
198
199 spy->id = id;
200 spy->type = type;
201 spy->func = func;
202 spy->ctx = ctx;
203 list_add_tail(&spy->sibling_node, &state->spy_head);
204
205 return 0;
206}
207
208int event_uninit(void)
209{
210 struct event_state *state = gd_event_state();
211 struct event_spy *spy, *next;
212
213 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node)
214 spy_free(spy);
215
216 return 0;
217}
218
219int event_init(void)
220{
221 struct event_state *state = gd_event_state();
222
223 INIT_LIST_HEAD(&state->spy_head);
224
225 return 0;
226}
227#endif /* EVENT_DYNAMIC */