blob: 55f6932ef62c57fd48f99d443ed355ff969c7484 [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",
Simon Glass3ee337a2022-03-04 08:43:03 -070031 "dm_pre_probe",
32 "dm_post_probe",
33 "dm_pre_remove",
34 "dm_post_remove",
Simon Glassf1c51912022-03-04 08:43:04 -070035
36 /* init hooks */
37 "misc_init_f",
Simon Glass4305fe72022-07-30 15:52:31 -060038
Christian Taedckedf369812023-07-20 09:27:24 +020039 /* Fpga load hook */
40 "fpga_load",
41
Simon Glass4305fe72022-07-30 15:52:31 -060042 /* fdt hooks */
43 "ft_fixup",
Sughosh Ganub780fa52022-10-21 18:16:01 +053044
45 /* main loop events */
46 "main_loop",
Simon Glassaa4bce92022-03-04 08:43:00 -070047};
48
49_Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
50#endif
51
Simon Glassd6db8942023-08-21 21:16:53 -060052const char *event_type_name(enum event_t type)
Simon Glassaa4bce92022-03-04 08:43:00 -070053{
54#if CONFIG_IS_ENABLED(EVENT_DEBUG)
55 return type_name[type];
56#else
57 return "(unknown)";
58#endif
59}
60
61static int notify_static(struct event *ev)
62{
63 struct evspy_info *start =
64 ll_entry_start(struct evspy_info, evspy_info);
65 const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
66 struct evspy_info *spy;
67
68 for (spy = start; spy != start + n_ents; spy++) {
69 if (spy->type == ev->type) {
70 int ret;
71
72 log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
73 event_type_name(ev->type), event_spy_id(spy));
Simon Glass3bfbedd2023-08-21 21:16:48 -060074 if (spy->flags & EVSPYF_SIMPLE) {
75 const struct evspy_info_simple *simple;
76
77 simple = (struct evspy_info_simple *)spy;
78 ret = simple->func();
79 } else {
80 ret = spy->func(NULL, ev);
81 }
Simon Glassaa4bce92022-03-04 08:43:00 -070082
83 /*
84 * TODO: Handle various return codes to
85 *
86 * - claim an event (no others will see it)
87 * - return an error from the event
88 */
89 if (ret)
90 return log_msg_ret("spy", ret);
91 }
92 }
93
94 return 0;
95}
96
97static int notify_dynamic(struct event *ev)
98{
99 struct event_state *state = gd_event_state();
100 struct event_spy *spy, *next;
101
102 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node) {
103 if (spy->type == ev->type) {
104 int ret;
105
106 log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
107 event_type_name(ev->type), spy->id);
108 ret = spy->func(spy->ctx, ev);
109
110 /*
111 * TODO: Handle various return codes to
112 *
113 * - claim an event (no others will see it)
114 * - return an error from the event
115 */
116 if (ret)
117 return log_msg_ret("spy", ret);
118 }
119 }
120
121 return 0;
122}
123
124int event_notify(enum event_t type, void *data, int size)
125{
126 struct event event;
127 int ret;
128
129 event.type = type;
130 if (size > sizeof(event.data))
131 return log_msg_ret("size", -E2BIG);
132 memcpy(&event.data, data, size);
133
134 ret = notify_static(&event);
135 if (ret)
Simon Glass1573cca2023-01-17 10:47:31 -0700136 return log_msg_ret("sta", ret);
Simon Glassaa4bce92022-03-04 08:43:00 -0700137
138 if (CONFIG_IS_ENABLED(EVENT_DYNAMIC)) {
139 ret = notify_dynamic(&event);
140 if (ret)
141 return log_msg_ret("dyn", ret);
142 }
143
144 return 0;
145}
146
147int event_notify_null(enum event_t type)
148{
149 return event_notify(type, NULL, 0);
150}
151
152void event_show_spy_list(void)
153{
154 struct evspy_info *start =
155 ll_entry_start(struct evspy_info, evspy_info);
156 const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
157 struct evspy_info *spy;
158 const int size = sizeof(ulong) * 2;
159
160 printf("Seq %-24s %*s %s\n", "Type", size, "Function", "ID");
161 for (spy = start; spy != start + n_ents; spy++) {
162 printf("%3x %-3x %-20s %*p %s\n", (uint)(spy - start),
163 spy->type, event_type_name(spy->type), size, spy->func,
164 event_spy_id(spy));
165 }
166}
167
Simon Glassa4d9fd12023-02-05 15:40:19 -0700168#if IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)
Ovidiu Panait145f2002022-05-15 21:40:29 +0300169int event_manual_reloc(void)
170{
171 struct evspy_info *spy, *end;
172
173 spy = ll_entry_start(struct evspy_info, evspy_info);
174 end = ll_entry_end(struct evspy_info, evspy_info);
175 for (; spy < end; spy++)
176 MANUAL_RELOC(spy->func);
177
178 return 0;
179}
180#endif
181
Simon Glassaa4bce92022-03-04 08:43:00 -0700182#if CONFIG_IS_ENABLED(EVENT_DYNAMIC)
183static void spy_free(struct event_spy *spy)
184{
185 list_del(&spy->sibling_node);
186}
187
188int event_register(const char *id, enum event_t type, event_handler_t func, void *ctx)
189{
190 struct event_state *state = gd_event_state();
191 struct event_spy *spy;
192
Simon Glassaa4bce92022-03-04 08:43:00 -0700193 spy = malloc(sizeof(*spy));
194 if (!spy)
195 return log_msg_ret("alloc", -ENOMEM);
196
197 spy->id = id;
198 spy->type = type;
199 spy->func = func;
200 spy->ctx = ctx;
201 list_add_tail(&spy->sibling_node, &state->spy_head);
202
203 return 0;
204}
205
206int event_uninit(void)
207{
208 struct event_state *state = gd_event_state();
209 struct event_spy *spy, *next;
210
211 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node)
212 spy_free(spy);
213
214 return 0;
215}
216
217int event_init(void)
218{
219 struct event_state *state = gd_event_state();
220
221 INIT_LIST_HEAD(&state->spy_head);
222
223 return 0;
224}
225#endif /* EVENT_DYNAMIC */