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 <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>
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",
31 	"dm_pre_probe",
32 	"dm_post_probe",
33 	"dm_pre_remove",
34 	"dm_post_remove",
35 
36 	/* init hooks */
37 	"misc_init_f",
38 
39 	/* fdt hooks */
40 	"ft_fixup",
41 
42 	/* main loop events */
43 	"main_loop",
44 };
45 
46 _Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
47 #endif
48 
event_type_name(enum event_t type)49 static 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 
notify_static(struct event * ev)58 static 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 
notify_dynamic(struct event * ev)87 static 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 
event_notify(enum event_t type,void * data,int size)114 int 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)
126 		return log_msg_ret("sta", ret);
127 
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 
event_notify_null(enum event_t type)137 int event_notify_null(enum event_t type)
138 {
139 	return event_notify(type, NULL, 0);
140 }
141 
event_show_spy_list(void)142 void 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 
158 #if IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)
event_manual_reloc(void)159 int 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 
172 #if CONFIG_IS_ENABLED(EVENT_DYNAMIC)
spy_free(struct event_spy * spy)173 static void spy_free(struct event_spy *spy)
174 {
175 	list_del(&spy->sibling_node);
176 }
177 
event_register(const char * id,enum event_t type,event_handler_t func,void * ctx)178 int 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 
183 	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 
event_uninit(void)196 int 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 
event_init(void)207 int 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 */
216