1 // 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 <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>
18 #include <linux/errno.h>
19 #include <linux/list.h>
20 #include <relocate.h>
21
22 DECLARE_GLOBAL_DATA_PTR;
23
24 #if CONFIG_IS_ENABLED(EVENT_DEBUG)
25 const char *const type_name[] = {
26 "none",
27 "test",
28
29 /* Events related to driver model */
30 "dm_post_init_f",
31 "dm_post_init_r",
32 "dm_pre_probe",
33 "dm_post_probe",
34 "dm_pre_remove",
35 "dm_post_remove",
36
37 /* init hooks */
38 "misc_init_f",
39 "fsp_init_r",
40 "settings_r",
41 "last_stage_init",
42
43 /* Fpga load hook */
44 "fpga_load",
45
46 /* fdt hooks */
47 "ft_fixup",
48
49 /* main loop events */
50 "main_loop",
51
52 /* livetree has been built */
53 "of_live_init",
54 };
55
56 _Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
57 #endif
58
event_type_name(enum event_t type)59 const char *event_type_name(enum event_t type)
60 {
61 #if CONFIG_IS_ENABLED(EVENT_DEBUG)
62 if (type < ARRAY_SIZE(type_name))
63 return type_name[type];
64 else
65 return "(unknown)";
66 #else
67 return "(unknown)";
68 #endif
69 }
70
notify_static(struct event * ev)71 static 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));
84 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 }
92
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
notify_dynamic(struct event * ev)107 static 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
event_notify(enum event_t type,void * data,int size)134 int 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)
146 return log_msg_ret("sta", ret);
147
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
event_notify_null(enum event_t type)157 int event_notify_null(enum event_t type)
158 {
159 return event_notify(type, NULL, 0);
160 }
161
event_show_spy_list(void)162 void 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)
spy_free(struct event_spy * spy)179 static void spy_free(struct event_spy *spy)
180 {
181 list_del(&spy->sibling_node);
182 }
183
event_register(const char * id,enum event_t type,event_handler_t func,void * ctx)184 int 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
189 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
event_uninit(void)202 int 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
event_init(void)213 int 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 */
222