blob: 8d7513eb10b61919e1e784481dfdcc076be14986 [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 Rinidec7ea02024-05-20 13:35:03 -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",
Caleb Connolly8ca0cf12025-04-11 14:47:38 +020051
52 /* livetree has been built */
53 "of_live_init",
Simon Glassaa4bce92022-03-04 08:43:00 -070054};
55
56_Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
57#endif
58
Simon Glassd6db8942023-08-21 21:16:53 -060059const char *event_type_name(enum event_t type)
Simon Glassaa4bce92022-03-04 08:43:00 -070060{
61#if CONFIG_IS_ENABLED(EVENT_DEBUG)
Heinrich Schuchardt81a89232024-01-28 08:58:55 +010062 if (type < ARRAY_SIZE(type_name))
63 return type_name[type];
64 else
65 return "(unknown)";
Simon Glassaa4bce92022-03-04 08:43:00 -070066#else
67 return "(unknown)";
68#endif
69}
70
71static int notify_static(struct event *ev)
72{
73 struct evspy_info *start =
74 ll_entry_start(struct evspy_info, evspy_info);
75 const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
76 struct evspy_info *spy;
77
78 for (spy = start; spy != start + n_ents; spy++) {
79 if (spy->type == ev->type) {
80 int ret;
81
82 log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
83 event_type_name(ev->type), event_spy_id(spy));
Simon Glass3bfbedd2023-08-21 21:16:48 -060084 if (spy->flags & EVSPYF_SIMPLE) {
85 const struct evspy_info_simple *simple;
86
87 simple = (struct evspy_info_simple *)spy;
88 ret = simple->func();
89 } else {
90 ret = spy->func(NULL, ev);
91 }
Simon Glassaa4bce92022-03-04 08:43:00 -070092
93 /*
94 * TODO: Handle various return codes to
95 *
96 * - claim an event (no others will see it)
97 * - return an error from the event
98 */
99 if (ret)
100 return log_msg_ret("spy", ret);
101 }
102 }
103
104 return 0;
105}
106
107static int notify_dynamic(struct event *ev)
108{
109 struct event_state *state = gd_event_state();
110 struct event_spy *spy, *next;
111
112 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node) {
113 if (spy->type == ev->type) {
114 int ret;
115
116 log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
117 event_type_name(ev->type), spy->id);
118 ret = spy->func(spy->ctx, ev);
119
120 /*
121 * TODO: Handle various return codes to
122 *
123 * - claim an event (no others will see it)
124 * - return an error from the event
125 */
126 if (ret)
127 return log_msg_ret("spy", ret);
128 }
129 }
130
131 return 0;
132}
133
134int event_notify(enum event_t type, void *data, int size)
135{
136 struct event event;
137 int ret;
138
139 event.type = type;
140 if (size > sizeof(event.data))
141 return log_msg_ret("size", -E2BIG);
142 memcpy(&event.data, data, size);
143
144 ret = notify_static(&event);
145 if (ret)
Simon Glass1573cca2023-01-17 10:47:31 -0700146 return log_msg_ret("sta", ret);
Simon Glassaa4bce92022-03-04 08:43:00 -0700147
148 if (CONFIG_IS_ENABLED(EVENT_DYNAMIC)) {
149 ret = notify_dynamic(&event);
150 if (ret)
151 return log_msg_ret("dyn", ret);
152 }
153
154 return 0;
155}
156
157int event_notify_null(enum event_t type)
158{
159 return event_notify(type, NULL, 0);
160}
161
162void event_show_spy_list(void)
163{
164 struct evspy_info *start =
165 ll_entry_start(struct evspy_info, evspy_info);
166 const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
167 struct evspy_info *spy;
168 const int size = sizeof(ulong) * 2;
169
170 printf("Seq %-24s %*s %s\n", "Type", size, "Function", "ID");
171 for (spy = start; spy != start + n_ents; spy++) {
172 printf("%3x %-3x %-20s %*p %s\n", (uint)(spy - start),
173 spy->type, event_type_name(spy->type), size, spy->func,
174 event_spy_id(spy));
175 }
176}
177
178#if CONFIG_IS_ENABLED(EVENT_DYNAMIC)
179static void spy_free(struct event_spy *spy)
180{
181 list_del(&spy->sibling_node);
182}
183
184int event_register(const char *id, enum event_t type, event_handler_t func, void *ctx)
185{
186 struct event_state *state = gd_event_state();
187 struct event_spy *spy;
188
Simon Glassaa4bce92022-03-04 08:43:00 -0700189 spy = malloc(sizeof(*spy));
190 if (!spy)
191 return log_msg_ret("alloc", -ENOMEM);
192
193 spy->id = id;
194 spy->type = type;
195 spy->func = func;
196 spy->ctx = ctx;
197 list_add_tail(&spy->sibling_node, &state->spy_head);
198
199 return 0;
200}
201
202int event_uninit(void)
203{
204 struct event_state *state = gd_event_state();
205 struct event_spy *spy, *next;
206
207 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node)
208 spy_free(spy);
209
210 return 0;
211}
212
213int event_init(void)
214{
215 struct event_state *state = gd_event_state();
216
217 INIT_LIST_HEAD(&state->spy_head);
218
219 return 0;
220}
221#endif /* EVENT_DYNAMIC */