blob: 6653300e6cf48db043f41064c71bc6539cd5cec9 [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",
Chanho Park27c7a622023-08-18 14:11:02 +090031 "dm_post_init_r",
Simon Glass5b896ed2022-03-04 08:43:03 -070032 "dm_pre_probe",
33 "dm_post_probe",
34 "dm_pre_remove",
35 "dm_post_remove",
Simon Glass42fdceb2022-03-04 08:43:04 -070036
37 /* init hooks */
38 "misc_init_f",
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
53static const char *event_type_name(enum event_t type)
54{
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));
75 ret = spy->func(NULL, ev);
76
77 /*
78 * TODO: Handle various return codes to
79 *
80 * - claim an event (no others will see it)
81 * - return an error from the event
82 */
83 if (ret)
84 return log_msg_ret("spy", ret);
85 }
86 }
87
88 return 0;
89}
90
91static int notify_dynamic(struct event *ev)
92{
93 struct event_state *state = gd_event_state();
94 struct event_spy *spy, *next;
95
96 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node) {
97 if (spy->type == ev->type) {
98 int ret;
99
100 log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
101 event_type_name(ev->type), spy->id);
102 ret = spy->func(spy->ctx, ev);
103
104 /*
105 * TODO: Handle various return codes to
106 *
107 * - claim an event (no others will see it)
108 * - return an error from the event
109 */
110 if (ret)
111 return log_msg_ret("spy", ret);
112 }
113 }
114
115 return 0;
116}
117
118int event_notify(enum event_t type, void *data, int size)
119{
120 struct event event;
121 int ret;
122
123 event.type = type;
124 if (size > sizeof(event.data))
125 return log_msg_ret("size", -E2BIG);
126 memcpy(&event.data, data, size);
127
128 ret = notify_static(&event);
129 if (ret)
Simon Glass19efd432023-01-17 10:47:31 -0700130 return log_msg_ret("sta", ret);
Simon Glass87a5d1b2022-03-04 08:43:00 -0700131
132 if (CONFIG_IS_ENABLED(EVENT_DYNAMIC)) {
133 ret = notify_dynamic(&event);
134 if (ret)
135 return log_msg_ret("dyn", ret);
136 }
137
138 return 0;
139}
140
141int event_notify_null(enum event_t type)
142{
143 return event_notify(type, NULL, 0);
144}
145
146void event_show_spy_list(void)
147{
148 struct evspy_info *start =
149 ll_entry_start(struct evspy_info, evspy_info);
150 const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
151 struct evspy_info *spy;
152 const int size = sizeof(ulong) * 2;
153
154 printf("Seq %-24s %*s %s\n", "Type", size, "Function", "ID");
155 for (spy = start; spy != start + n_ents; spy++) {
156 printf("%3x %-3x %-20s %*p %s\n", (uint)(spy - start),
157 spy->type, event_type_name(spy->type), size, spy->func,
158 event_spy_id(spy));
159 }
160}
161
Simon Glass00ba40f2023-02-05 15:40:19 -0700162#if IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)
Ovidiu Panaitcebc8162022-05-15 21:40:29 +0300163int event_manual_reloc(void)
164{
165 struct evspy_info *spy, *end;
166
167 spy = ll_entry_start(struct evspy_info, evspy_info);
168 end = ll_entry_end(struct evspy_info, evspy_info);
169 for (; spy < end; spy++)
170 MANUAL_RELOC(spy->func);
171
172 return 0;
173}
174#endif
175
Simon Glass87a5d1b2022-03-04 08:43:00 -0700176#if CONFIG_IS_ENABLED(EVENT_DYNAMIC)
177static void spy_free(struct event_spy *spy)
178{
179 list_del(&spy->sibling_node);
180}
181
182int event_register(const char *id, enum event_t type, event_handler_t func, void *ctx)
183{
184 struct event_state *state = gd_event_state();
185 struct event_spy *spy;
186
Simon Glass87a5d1b2022-03-04 08:43:00 -0700187 spy = malloc(sizeof(*spy));
188 if (!spy)
189 return log_msg_ret("alloc", -ENOMEM);
190
191 spy->id = id;
192 spy->type = type;
193 spy->func = func;
194 spy->ctx = ctx;
195 list_add_tail(&spy->sibling_node, &state->spy_head);
196
197 return 0;
198}
199
200int event_uninit(void)
201{
202 struct event_state *state = gd_event_state();
203 struct event_spy *spy, *next;
204
205 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node)
206 spy_free(spy);
207
208 return 0;
209}
210
211int event_init(void)
212{
213 struct event_state *state = gd_event_state();
214
215 INIT_LIST_HEAD(&state->spy_head);
216
217 return 0;
218}
219#endif /* EVENT_DYNAMIC */