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