blob: 3224e2812224da85b0b61c0f3d758e4427bfe577 [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
52static const char *event_type_name(enum event_t type)
53{
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));
74 ret = spy->func(NULL, ev);
75
76 /*
77 * TODO: Handle various return codes to
78 *
79 * - claim an event (no others will see it)
80 * - return an error from the event
81 */
82 if (ret)
83 return log_msg_ret("spy", ret);
84 }
85 }
86
87 return 0;
88}
89
90static int notify_dynamic(struct event *ev)
91{
92 struct event_state *state = gd_event_state();
93 struct event_spy *spy, *next;
94
95 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node) {
96 if (spy->type == ev->type) {
97 int ret;
98
99 log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
100 event_type_name(ev->type), spy->id);
101 ret = spy->func(spy->ctx, ev);
102
103 /*
104 * TODO: Handle various return codes to
105 *
106 * - claim an event (no others will see it)
107 * - return an error from the event
108 */
109 if (ret)
110 return log_msg_ret("spy", ret);
111 }
112 }
113
114 return 0;
115}
116
117int event_notify(enum event_t type, void *data, int size)
118{
119 struct event event;
120 int ret;
121
122 event.type = type;
123 if (size > sizeof(event.data))
124 return log_msg_ret("size", -E2BIG);
125 memcpy(&event.data, data, size);
126
127 ret = notify_static(&event);
128 if (ret)
Simon Glass1573cca2023-01-17 10:47:31 -0700129 return log_msg_ret("sta", ret);
Simon Glassaa4bce92022-03-04 08:43:00 -0700130
131 if (CONFIG_IS_ENABLED(EVENT_DYNAMIC)) {
132 ret = notify_dynamic(&event);
133 if (ret)
134 return log_msg_ret("dyn", ret);
135 }
136
137 return 0;
138}
139
140int event_notify_null(enum event_t type)
141{
142 return event_notify(type, NULL, 0);
143}
144
145void event_show_spy_list(void)
146{
147 struct evspy_info *start =
148 ll_entry_start(struct evspy_info, evspy_info);
149 const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
150 struct evspy_info *spy;
151 const int size = sizeof(ulong) * 2;
152
153 printf("Seq %-24s %*s %s\n", "Type", size, "Function", "ID");
154 for (spy = start; spy != start + n_ents; spy++) {
155 printf("%3x %-3x %-20s %*p %s\n", (uint)(spy - start),
156 spy->type, event_type_name(spy->type), size, spy->func,
157 event_spy_id(spy));
158 }
159}
160
Simon Glassa4d9fd12023-02-05 15:40:19 -0700161#if IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)
Ovidiu Panait145f2002022-05-15 21:40:29 +0300162int event_manual_reloc(void)
163{
164 struct evspy_info *spy, *end;
165
166 spy = ll_entry_start(struct evspy_info, evspy_info);
167 end = ll_entry_end(struct evspy_info, evspy_info);
168 for (; spy < end; spy++)
169 MANUAL_RELOC(spy->func);
170
171 return 0;
172}
173#endif
174
Simon Glassaa4bce92022-03-04 08:43:00 -0700175#if CONFIG_IS_ENABLED(EVENT_DYNAMIC)
176static void spy_free(struct event_spy *spy)
177{
178 list_del(&spy->sibling_node);
179}
180
181int event_register(const char *id, enum event_t type, event_handler_t func, void *ctx)
182{
183 struct event_state *state = gd_event_state();
184 struct event_spy *spy;
185
Simon Glassaa4bce92022-03-04 08:43:00 -0700186 spy = malloc(sizeof(*spy));
187 if (!spy)
188 return log_msg_ret("alloc", -ENOMEM);
189
190 spy->id = id;
191 spy->type = type;
192 spy->func = func;
193 spy->ctx = ctx;
194 list_add_tail(&spy->sibling_node, &state->spy_head);
195
196 return 0;
197}
198
199int event_uninit(void)
200{
201 struct event_state *state = gd_event_state();
202 struct event_spy *spy, *next;
203
204 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node)
205 spy_free(spy);
206
207 return 0;
208}
209
210int event_init(void)
211{
212 struct event_state *state = gd_event_state();
213
214 INIT_LIST_HEAD(&state->spy_head);
215
216 return 0;
217}
218#endif /* EVENT_DYNAMIC */