blob: 3e345509783918fe3742074ba2785f87e0809b05 [file] [log] [blame]
Simon Glass87a5d1b2022-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 Panaitcebc8162022-05-15 21:40:29 +030020#include <relocate.h>
Simon Glass87a5d1b2022-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 Glass5b896ed2022-03-04 08:43:03 -070028
29 /* Events related to driver model */
Simon Glass7fe32b32022-03-04 08:43:05 -070030 "dm_post_init",
Simon Glass5b896ed2022-03-04 08:43:03 -070031 "dm_pre_probe",
32 "dm_post_probe",
33 "dm_pre_remove",
34 "dm_post_remove",
Simon Glass42fdceb2022-03-04 08:43:04 -070035
36 /* init hooks */
37 "misc_init_f",
Simon Glass98887ab2022-07-30 15:52:31 -060038
39 /* fdt hooks */
40 "ft_fixup",
Simon Glass87a5d1b2022-03-04 08:43:00 -070041};
42
43_Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
44#endif
45
46static const char *event_type_name(enum event_t type)
47{
48#if CONFIG_IS_ENABLED(EVENT_DEBUG)
49 return type_name[type];
50#else
51 return "(unknown)";
52#endif
53}
54
55static int notify_static(struct event *ev)
56{
57 struct evspy_info *start =
58 ll_entry_start(struct evspy_info, evspy_info);
59 const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
60 struct evspy_info *spy;
61
62 for (spy = start; spy != start + n_ents; spy++) {
63 if (spy->type == ev->type) {
64 int ret;
65
66 log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
67 event_type_name(ev->type), event_spy_id(spy));
68 ret = spy->func(NULL, ev);
69
70 /*
71 * TODO: Handle various return codes to
72 *
73 * - claim an event (no others will see it)
74 * - return an error from the event
75 */
76 if (ret)
77 return log_msg_ret("spy", ret);
78 }
79 }
80
81 return 0;
82}
83
84static int notify_dynamic(struct event *ev)
85{
86 struct event_state *state = gd_event_state();
87 struct event_spy *spy, *next;
88
89 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node) {
90 if (spy->type == ev->type) {
91 int ret;
92
93 log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
94 event_type_name(ev->type), spy->id);
95 ret = spy->func(spy->ctx, ev);
96
97 /*
98 * TODO: Handle various return codes to
99 *
100 * - claim an event (no others will see it)
101 * - return an error from the event
102 */
103 if (ret)
104 return log_msg_ret("spy", ret);
105 }
106 }
107
108 return 0;
109}
110
111int event_notify(enum event_t type, void *data, int size)
112{
113 struct event event;
114 int ret;
115
116 event.type = type;
117 if (size > sizeof(event.data))
118 return log_msg_ret("size", -E2BIG);
119 memcpy(&event.data, data, size);
120
121 ret = notify_static(&event);
122 if (ret)
123 return log_msg_ret("dyn", ret);
124
125 if (CONFIG_IS_ENABLED(EVENT_DYNAMIC)) {
126 ret = notify_dynamic(&event);
127 if (ret)
128 return log_msg_ret("dyn", ret);
129 }
130
131 return 0;
132}
133
134int event_notify_null(enum event_t type)
135{
136 return event_notify(type, NULL, 0);
137}
138
139void event_show_spy_list(void)
140{
141 struct evspy_info *start =
142 ll_entry_start(struct evspy_info, evspy_info);
143 const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
144 struct evspy_info *spy;
145 const int size = sizeof(ulong) * 2;
146
147 printf("Seq %-24s %*s %s\n", "Type", size, "Function", "ID");
148 for (spy = start; spy != start + n_ents; spy++) {
149 printf("%3x %-3x %-20s %*p %s\n", (uint)(spy - start),
150 spy->type, event_type_name(spy->type), size, spy->func,
151 event_spy_id(spy));
152 }
153}
154
Ovidiu Panaitcebc8162022-05-15 21:40:29 +0300155#if CONFIG_IS_ENABLED(NEEDS_MANUAL_RELOC)
156int event_manual_reloc(void)
157{
158 struct evspy_info *spy, *end;
159
160 spy = ll_entry_start(struct evspy_info, evspy_info);
161 end = ll_entry_end(struct evspy_info, evspy_info);
162 for (; spy < end; spy++)
163 MANUAL_RELOC(spy->func);
164
165 return 0;
166}
167#endif
168
Simon Glass87a5d1b2022-03-04 08:43:00 -0700169#if CONFIG_IS_ENABLED(EVENT_DYNAMIC)
170static void spy_free(struct event_spy *spy)
171{
172 list_del(&spy->sibling_node);
173}
174
175int event_register(const char *id, enum event_t type, event_handler_t func, void *ctx)
176{
177 struct event_state *state = gd_event_state();
178 struct event_spy *spy;
179
Simon Glass87a5d1b2022-03-04 08:43:00 -0700180 spy = malloc(sizeof(*spy));
181 if (!spy)
182 return log_msg_ret("alloc", -ENOMEM);
183
184 spy->id = id;
185 spy->type = type;
186 spy->func = func;
187 spy->ctx = ctx;
188 list_add_tail(&spy->sibling_node, &state->spy_head);
189
190 return 0;
191}
192
193int event_uninit(void)
194{
195 struct event_state *state = gd_event_state();
196 struct event_spy *spy, *next;
197
198 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node)
199 spy_free(spy);
200
201 return 0;
202}
203
204int event_init(void)
205{
206 struct event_state *state = gd_event_state();
207
208 INIT_LIST_HEAD(&state->spy_head);
209
210 return 0;
211}
212#endif /* EVENT_DYNAMIC */