Merge branch '2023-01-24-bootstd-allow-migration-from-distro_bootcmd-script'
[platform/kernel/u-boot.git] / common / event.c
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
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
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
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
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
137 int event_notify_null(enum event_t type)
138 {
139         return event_notify(type, NULL, 0);
140 }
141
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 CONFIG_IS_ENABLED(NEEDS_MANUAL_RELOC)
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)
173 static void spy_free(struct event_spy *spy)
174 {
175         list_del(&spy->sibling_node);
176 }
177
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
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
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 */