Merge branch '2022-08-10-assorted-updates'
[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
40 _Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
41 #endif
42
43 static 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
52 static 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
81 static 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
108 int 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
131 int event_notify_null(enum event_t type)
132 {
133         return event_notify(type, NULL, 0);
134 }
135
136 void 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
152 #if CONFIG_IS_ENABLED(NEEDS_MANUAL_RELOC)
153 int 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
166 #if CONFIG_IS_ENABLED(EVENT_DYNAMIC)
167 static void spy_free(struct event_spy *spy)
168 {
169         list_del(&spy->sibling_node);
170 }
171
172 int 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
177         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
190 int 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
201 int 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 */