blob: dda569d447851f559a83f98fb7b1f3543156eab5 [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
Simon Glassaa4bce92022-03-04 08:43:00 -070012#include <event.h>
13#include <event_internal.h>
14#include <log.h>
15#include <linker_lists.h>
16#include <malloc.h>
17#include <asm/global_data.h>
Tom Rini728cb882024-04-27 08:11:00 -060018#include <linux/errno.h>
Simon Glassaa4bce92022-03-04 08:43:00 -070019#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",
Artur Rojekadd76342023-10-18 16:00:57 +020040 "settings_r",
Simon Glass1cedca12023-08-21 21:17:01 -060041 "last_stage_init",
Simon Glass4305fe72022-07-30 15:52:31 -060042
Christian Taedckedf369812023-07-20 09:27:24 +020043 /* Fpga load hook */
44 "fpga_load",
45
Simon Glass4305fe72022-07-30 15:52:31 -060046 /* fdt hooks */
47 "ft_fixup",
Sughosh Ganub780fa52022-10-21 18:16:01 +053048
49 /* main loop events */
50 "main_loop",
Simon Glassaa4bce92022-03-04 08:43:00 -070051};
52
53_Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
54#endif
55
Simon Glassd6db8942023-08-21 21:16:53 -060056const char *event_type_name(enum event_t type)
Simon Glassaa4bce92022-03-04 08:43:00 -070057{
58#if CONFIG_IS_ENABLED(EVENT_DEBUG)
Heinrich Schuchardt81a89232024-01-28 08:58:55 +010059 if (type < ARRAY_SIZE(type_name))
60 return type_name[type];
61 else
62 return "(unknown)";
Simon Glassaa4bce92022-03-04 08:43:00 -070063#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));
Simon Glass3bfbedd2023-08-21 21:16:48 -060081 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 }
Simon Glassaa4bce92022-03-04 08:43:00 -070089
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)
Simon Glass1573cca2023-01-17 10:47:31 -0700143 return log_msg_ret("sta", ret);
Simon Glassaa4bce92022-03-04 08:43:00 -0700144
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
Simon Glassaa4bce92022-03-04 08:43:00 -0700186 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 */