blob: 164c95f8f52cc8ec648f24a1db2ae1b4141ce710 [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 */
Simon Glassfc557362022-03-04 08:43:05 -070030 "dm_post_init",
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
39 /* fdt hooks */
40 "ft_fixup",
Sughosh Ganub780fa52022-10-21 18:16:01 +053041
42 /* main loop events */
43 "main_loop",
Simon Glassaa4bce92022-03-04 08:43:00 -070044};
45
46_Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
47#endif
48
49static const char *event_type_name(enum event_t type)
50{
51#if CONFIG_IS_ENABLED(EVENT_DEBUG)
52 return type_name[type];
53#else
54 return "(unknown)";
55#endif
56}
57
58static int notify_static(struct event *ev)
59{
60 struct evspy_info *start =
61 ll_entry_start(struct evspy_info, evspy_info);
62 const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
63 struct evspy_info *spy;
64
65 for (spy = start; spy != start + n_ents; spy++) {
66 if (spy->type == ev->type) {
67 int ret;
68
69 log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
70 event_type_name(ev->type), event_spy_id(spy));
71 ret = spy->func(NULL, ev);
72
73 /*
74 * TODO: Handle various return codes to
75 *
76 * - claim an event (no others will see it)
77 * - return an error from the event
78 */
79 if (ret)
80 return log_msg_ret("spy", ret);
81 }
82 }
83
84 return 0;
85}
86
87static int notify_dynamic(struct event *ev)
88{
89 struct event_state *state = gd_event_state();
90 struct event_spy *spy, *next;
91
92 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node) {
93 if (spy->type == ev->type) {
94 int ret;
95
96 log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
97 event_type_name(ev->type), spy->id);
98 ret = spy->func(spy->ctx, ev);
99
100 /*
101 * TODO: Handle various return codes to
102 *
103 * - claim an event (no others will see it)
104 * - return an error from the event
105 */
106 if (ret)
107 return log_msg_ret("spy", ret);
108 }
109 }
110
111 return 0;
112}
113
114int event_notify(enum event_t type, void *data, int size)
115{
116 struct event event;
117 int ret;
118
119 event.type = type;
120 if (size > sizeof(event.data))
121 return log_msg_ret("size", -E2BIG);
122 memcpy(&event.data, data, size);
123
124 ret = notify_static(&event);
125 if (ret)
Simon Glass1573cca2023-01-17 10:47:31 -0700126 return log_msg_ret("sta", ret);
Simon Glassaa4bce92022-03-04 08:43:00 -0700127
128 if (CONFIG_IS_ENABLED(EVENT_DYNAMIC)) {
129 ret = notify_dynamic(&event);
130 if (ret)
131 return log_msg_ret("dyn", ret);
132 }
133
134 return 0;
135}
136
137int event_notify_null(enum event_t type)
138{
139 return event_notify(type, NULL, 0);
140}
141
142void event_show_spy_list(void)
143{
144 struct evspy_info *start =
145 ll_entry_start(struct evspy_info, evspy_info);
146 const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
147 struct evspy_info *spy;
148 const int size = sizeof(ulong) * 2;
149
150 printf("Seq %-24s %*s %s\n", "Type", size, "Function", "ID");
151 for (spy = start; spy != start + n_ents; spy++) {
152 printf("%3x %-3x %-20s %*p %s\n", (uint)(spy - start),
153 spy->type, event_type_name(spy->type), size, spy->func,
154 event_spy_id(spy));
155 }
156}
157
Simon Glassa4d9fd12023-02-05 15:40:19 -0700158#if IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)
Ovidiu Panait145f2002022-05-15 21:40:29 +0300159int event_manual_reloc(void)
160{
161 struct evspy_info *spy, *end;
162
163 spy = ll_entry_start(struct evspy_info, evspy_info);
164 end = ll_entry_end(struct evspy_info, evspy_info);
165 for (; spy < end; spy++)
166 MANUAL_RELOC(spy->func);
167
168 return 0;
169}
170#endif
171
Simon Glassaa4bce92022-03-04 08:43:00 -0700172#if CONFIG_IS_ENABLED(EVENT_DYNAMIC)
173static void spy_free(struct event_spy *spy)
174{
175 list_del(&spy->sibling_node);
176}
177
178int event_register(const char *id, enum event_t type, event_handler_t func, void *ctx)
179{
180 struct event_state *state = gd_event_state();
181 struct event_spy *spy;
182
Simon Glassaa4bce92022-03-04 08:43:00 -0700183 spy = malloc(sizeof(*spy));
184 if (!spy)
185 return log_msg_ret("alloc", -ENOMEM);
186
187 spy->id = id;
188 spy->type = type;
189 spy->func = func;
190 spy->ctx = ctx;
191 list_add_tail(&spy->sibling_node, &state->spy_head);
192
193 return 0;
194}
195
196int event_uninit(void)
197{
198 struct event_state *state = gd_event_state();
199 struct event_spy *spy, *next;
200
201 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node)
202 spy_free(spy);
203
204 return 0;
205}
206
207int event_init(void)
208{
209 struct event_state *state = gd_event_state();
210
211 INIT_LIST_HEAD(&state->spy_head);
212
213 return 0;
214}
215#endif /* EVENT_DYNAMIC */