1 // 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 <event.h>
13 #include <event_internal.h>
14 #include <log.h>
15 #include <linker_lists.h>
16 #include <malloc.h>
17 #include <asm/global_data.h>
18 #include <linux/errno.h>
19 #include <linux/list.h>
20 #include <relocate.h>
21 
22 DECLARE_GLOBAL_DATA_PTR;
23 
24 #if CONFIG_IS_ENABLED(EVENT_DEBUG)
25 const char *const type_name[] = {
26 	"none",
27 	"test",
28 
29 	/* Events related to driver model */
30 	"dm_post_init_f",
31 	"dm_post_init_r",
32 	"dm_pre_probe",
33 	"dm_post_probe",
34 	"dm_pre_remove",
35 	"dm_post_remove",
36 
37 	/* init hooks */
38 	"misc_init_f",
39 	"fsp_init_r",
40 	"settings_r",
41 	"last_stage_init",
42 
43 	/* Fpga load hook */
44 	"fpga_load",
45 
46 	/* fdt hooks */
47 	"ft_fixup",
48 
49 	/* main loop events */
50 	"main_loop",
51 
52 	/* livetree has been built */
53 	"of_live_init",
54 };
55 
56 _Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
57 #endif
58 
event_type_name(enum event_t type)59 const char *event_type_name(enum event_t type)
60 {
61 #if CONFIG_IS_ENABLED(EVENT_DEBUG)
62 	if (type < ARRAY_SIZE(type_name))
63 		return type_name[type];
64 	else
65 		return "(unknown)";
66 #else
67 	return "(unknown)";
68 #endif
69 }
70 
notify_static(struct event * ev)71 static int notify_static(struct event *ev)
72 {
73 	struct evspy_info *start =
74 		ll_entry_start(struct evspy_info, evspy_info);
75 	const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
76 	struct evspy_info *spy;
77 
78 	for (spy = start; spy != start + n_ents; spy++) {
79 		if (spy->type == ev->type) {
80 			int ret;
81 
82 			log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
83 				  event_type_name(ev->type), event_spy_id(spy));
84 			if (spy->flags & EVSPYF_SIMPLE) {
85 				const struct evspy_info_simple *simple;
86 
87 				simple = (struct evspy_info_simple *)spy;
88 				ret = simple->func();
89 			} else {
90 				ret = spy->func(NULL, ev);
91 			}
92 
93 			/*
94 			 * TODO: Handle various return codes to
95 			 *
96 			 * - claim an event (no others will see it)
97 			 * - return an error from the event
98 			 */
99 			if (ret)
100 				return log_msg_ret("spy", ret);
101 		}
102 	}
103 
104 	return 0;
105 }
106 
notify_dynamic(struct event * ev)107 static int notify_dynamic(struct event *ev)
108 {
109 	struct event_state *state = gd_event_state();
110 	struct event_spy *spy, *next;
111 
112 	list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node) {
113 		if (spy->type == ev->type) {
114 			int ret;
115 
116 			log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
117 				  event_type_name(ev->type), spy->id);
118 			ret = spy->func(spy->ctx, ev);
119 
120 			/*
121 			 * TODO: Handle various return codes to
122 			 *
123 			 * - claim an event (no others will see it)
124 			 * - return an error from the event
125 			 */
126 			if (ret)
127 				return log_msg_ret("spy", ret);
128 		}
129 	}
130 
131 	return 0;
132 }
133 
event_notify(enum event_t type,void * data,int size)134 int event_notify(enum event_t type, void *data, int size)
135 {
136 	struct event event;
137 	int ret;
138 
139 	event.type = type;
140 	if (size > sizeof(event.data))
141 		return log_msg_ret("size", -E2BIG);
142 	memcpy(&event.data, data, size);
143 
144 	ret = notify_static(&event);
145 	if (ret)
146 		return log_msg_ret("sta", ret);
147 
148 	if (CONFIG_IS_ENABLED(EVENT_DYNAMIC)) {
149 		ret = notify_dynamic(&event);
150 		if (ret)
151 			return log_msg_ret("dyn", ret);
152 	}
153 
154 	return 0;
155 }
156 
event_notify_null(enum event_t type)157 int event_notify_null(enum event_t type)
158 {
159 	return event_notify(type, NULL, 0);
160 }
161 
event_show_spy_list(void)162 void event_show_spy_list(void)
163 {
164 	struct evspy_info *start =
165 		ll_entry_start(struct evspy_info, evspy_info);
166 	const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
167 	struct evspy_info *spy;
168 	const int size = sizeof(ulong) * 2;
169 
170 	printf("Seq  %-24s  %*s  %s\n", "Type", size, "Function", "ID");
171 	for (spy = start; spy != start + n_ents; spy++) {
172 		printf("%3x  %-3x %-20s  %*p  %s\n", (uint)(spy - start),
173 		       spy->type, event_type_name(spy->type), size, spy->func,
174 		       event_spy_id(spy));
175 	}
176 }
177 
178 #if CONFIG_IS_ENABLED(EVENT_DYNAMIC)
spy_free(struct event_spy * spy)179 static void spy_free(struct event_spy *spy)
180 {
181 	list_del(&spy->sibling_node);
182 }
183 
event_register(const char * id,enum event_t type,event_handler_t func,void * ctx)184 int event_register(const char *id, enum event_t type, event_handler_t func, void *ctx)
185 {
186 	struct event_state *state = gd_event_state();
187 	struct event_spy *spy;
188 
189 	spy = malloc(sizeof(*spy));
190 	if (!spy)
191 		return log_msg_ret("alloc", -ENOMEM);
192 
193 	spy->id = id;
194 	spy->type = type;
195 	spy->func = func;
196 	spy->ctx = ctx;
197 	list_add_tail(&spy->sibling_node, &state->spy_head);
198 
199 	return 0;
200 }
201 
event_uninit(void)202 int event_uninit(void)
203 {
204 	struct event_state *state = gd_event_state();
205 	struct event_spy *spy, *next;
206 
207 	list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node)
208 		spy_free(spy);
209 
210 	return 0;
211 }
212 
event_init(void)213 int event_init(void)
214 {
215 	struct event_state *state = gd_event_state();
216 
217 	INIT_LIST_HEAD(&state->spy_head);
218 
219 	return 0;
220 }
221 #endif /* EVENT_DYNAMIC */
222