blob: d11b37a1d802a9d1480d2211a70a07ed7f4b08ea [file] [log] [blame]
Simon Glassaa4bce92022-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 Panait145f2002022-05-15 21:40:29 +030020#include <relocate.h>
Simon Glassaa4bce92022-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 Glass3ee337a2022-03-04 08:43:03 -070028
29 /* Events related to driver model */
Jaehoon Chung74cd2d82023-08-01 19:17:00 +090030 "dm_post_init_f",
Chanho Park5865a002023-08-18 14:11:02 +090031 "dm_post_init_r",
Simon Glass3ee337a2022-03-04 08:43:03 -070032 "dm_pre_probe",
33 "dm_post_probe",
34 "dm_pre_remove",
35 "dm_post_remove",
Simon Glassf1c51912022-03-04 08:43:04 -070036
37 /* init hooks */
38 "misc_init_f",
Simon Glassfcebb7b2023-08-21 21:16:59 -060039 "fsp_init_r",
Simon Glass1cedca12023-08-21 21:17:01 -060040 "last_stage_init",
Simon Glass4305fe72022-07-30 15:52:31 -060041
Christian Taedckedf369812023-07-20 09:27:24 +020042 /* Fpga load hook */
43 "fpga_load",
44
Simon Glass4305fe72022-07-30 15:52:31 -060045 /* fdt hooks */
46 "ft_fixup",
Sughosh Ganub780fa52022-10-21 18:16:01 +053047
48 /* main loop events */
49 "main_loop",
Simon Glassaa4bce92022-03-04 08:43:00 -070050};
51
52_Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
53#endif
54
Simon Glassd6db8942023-08-21 21:16:53 -060055const char *event_type_name(enum event_t type)
Simon Glassaa4bce92022-03-04 08:43:00 -070056{
57#if CONFIG_IS_ENABLED(EVENT_DEBUG)
58 return type_name[type];
59#else
60 return "(unknown)";
61#endif
62}
63
64static int notify_static(struct event *ev)
65{
66 struct evspy_info *start =
67 ll_entry_start(struct evspy_info, evspy_info);
68 const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
69 struct evspy_info *spy;
70
71 for (spy = start; spy != start + n_ents; spy++) {
72 if (spy->type == ev->type) {
73 int ret;
74
75 log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
76 event_type_name(ev->type), event_spy_id(spy));
Simon Glass3bfbedd2023-08-21 21:16:48 -060077 if (spy->flags & EVSPYF_SIMPLE) {
78 const struct evspy_info_simple *simple;
79
80 simple = (struct evspy_info_simple *)spy;
81 ret = simple->func();
82 } else {
83 ret = spy->func(NULL, ev);
84 }
Simon Glassaa4bce92022-03-04 08:43:00 -070085
86 /*
87 * TODO: Handle various return codes to
88 *
89 * - claim an event (no others will see it)
90 * - return an error from the event
91 */
92 if (ret)
93 return log_msg_ret("spy", ret);
94 }
95 }
96
97 return 0;
98}
99
100static int notify_dynamic(struct event *ev)
101{
102 struct event_state *state = gd_event_state();
103 struct event_spy *spy, *next;
104
105 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node) {
106 if (spy->type == ev->type) {
107 int ret;
108
109 log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
110 event_type_name(ev->type), spy->id);
111 ret = spy->func(spy->ctx, ev);
112
113 /*
114 * TODO: Handle various return codes to
115 *
116 * - claim an event (no others will see it)
117 * - return an error from the event
118 */
119 if (ret)
120 return log_msg_ret("spy", ret);
121 }
122 }
123
124 return 0;
125}
126
127int event_notify(enum event_t type, void *data, int size)
128{
129 struct event event;
130 int ret;
131
132 event.type = type;
133 if (size > sizeof(event.data))
134 return log_msg_ret("size", -E2BIG);
135 memcpy(&event.data, data, size);
136
137 ret = notify_static(&event);
138 if (ret)
Simon Glass1573cca2023-01-17 10:47:31 -0700139 return log_msg_ret("sta", ret);
Simon Glassaa4bce92022-03-04 08:43:00 -0700140
141 if (CONFIG_IS_ENABLED(EVENT_DYNAMIC)) {
142 ret = notify_dynamic(&event);
143 if (ret)
144 return log_msg_ret("dyn", ret);
145 }
146
147 return 0;
148}
149
150int event_notify_null(enum event_t type)
151{
152 return event_notify(type, NULL, 0);
153}
154
155void event_show_spy_list(void)
156{
157 struct evspy_info *start =
158 ll_entry_start(struct evspy_info, evspy_info);
159 const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
160 struct evspy_info *spy;
161 const int size = sizeof(ulong) * 2;
162
163 printf("Seq %-24s %*s %s\n", "Type", size, "Function", "ID");
164 for (spy = start; spy != start + n_ents; spy++) {
165 printf("%3x %-3x %-20s %*p %s\n", (uint)(spy - start),
166 spy->type, event_type_name(spy->type), size, spy->func,
167 event_spy_id(spy));
168 }
169}
170
Simon Glassa4d9fd12023-02-05 15:40:19 -0700171#if IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)
Ovidiu Panait145f2002022-05-15 21:40:29 +0300172int event_manual_reloc(void)
173{
174 struct evspy_info *spy, *end;
175
176 spy = ll_entry_start(struct evspy_info, evspy_info);
177 end = ll_entry_end(struct evspy_info, evspy_info);
178 for (; spy < end; spy++)
179 MANUAL_RELOC(spy->func);
180
181 return 0;
182}
183#endif
184
Simon Glassaa4bce92022-03-04 08:43:00 -0700185#if CONFIG_IS_ENABLED(EVENT_DYNAMIC)
186static void spy_free(struct event_spy *spy)
187{
188 list_del(&spy->sibling_node);
189}
190
191int event_register(const char *id, enum event_t type, event_handler_t func, void *ctx)
192{
193 struct event_state *state = gd_event_state();
194 struct event_spy *spy;
195
Simon Glassaa4bce92022-03-04 08:43:00 -0700196 spy = malloc(sizeof(*spy));
197 if (!spy)
198 return log_msg_ret("alloc", -ENOMEM);
199
200 spy->id = id;
201 spy->type = type;
202 spy->func = func;
203 spy->ctx = ctx;
204 list_add_tail(&spy->sibling_node, &state->spy_head);
205
206 return 0;
207}
208
209int event_uninit(void)
210{
211 struct event_state *state = gd_event_state();
212 struct event_spy *spy, *next;
213
214 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node)
215 spy_free(spy);
216
217 return 0;
218}
219
220int event_init(void)
221{
222 struct event_state *state = gd_event_state();
223
224 INIT_LIST_HEAD(&state->spy_head);
225
226 return 0;
227}
228#endif /* EVENT_DYNAMIC */