]> Git Repo - J-u-boot.git/blob - common/event.c
event: Support a simple spy record
[J-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 <[email protected]>
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_f",
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         /* Fpga load hook */
40         "fpga_load",
41
42         /* fdt hooks */
43         "ft_fixup",
44
45         /* main loop events */
46         "main_loop",
47 };
48
49 _Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
50 #endif
51
52 static const char *event_type_name(enum event_t type)
53 {
54 #if CONFIG_IS_ENABLED(EVENT_DEBUG)
55         return type_name[type];
56 #else
57         return "(unknown)";
58 #endif
59 }
60
61 static int notify_static(struct event *ev)
62 {
63         struct evspy_info *start =
64                 ll_entry_start(struct evspy_info, evspy_info);
65         const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
66         struct evspy_info *spy;
67
68         for (spy = start; spy != start + n_ents; spy++) {
69                 if (spy->type == ev->type) {
70                         int ret;
71
72                         log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
73                                   event_type_name(ev->type), event_spy_id(spy));
74                         if (spy->flags & EVSPYF_SIMPLE) {
75                                 const struct evspy_info_simple *simple;
76
77                                 simple = (struct evspy_info_simple *)spy;
78                                 ret = simple->func();
79                         } else {
80                                 ret = spy->func(NULL, ev);
81                         }
82
83                         /*
84                          * TODO: Handle various return codes to
85                          *
86                          * - claim an event (no others will see it)
87                          * - return an error from the event
88                          */
89                         if (ret)
90                                 return log_msg_ret("spy", ret);
91                 }
92         }
93
94         return 0;
95 }
96
97 static int notify_dynamic(struct event *ev)
98 {
99         struct event_state *state = gd_event_state();
100         struct event_spy *spy, *next;
101
102         list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node) {
103                 if (spy->type == ev->type) {
104                         int ret;
105
106                         log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
107                                   event_type_name(ev->type), spy->id);
108                         ret = spy->func(spy->ctx, ev);
109
110                         /*
111                          * TODO: Handle various return codes to
112                          *
113                          * - claim an event (no others will see it)
114                          * - return an error from the event
115                          */
116                         if (ret)
117                                 return log_msg_ret("spy", ret);
118                 }
119         }
120
121         return 0;
122 }
123
124 int event_notify(enum event_t type, void *data, int size)
125 {
126         struct event event;
127         int ret;
128
129         event.type = type;
130         if (size > sizeof(event.data))
131                 return log_msg_ret("size", -E2BIG);
132         memcpy(&event.data, data, size);
133
134         ret = notify_static(&event);
135         if (ret)
136                 return log_msg_ret("sta", ret);
137
138         if (CONFIG_IS_ENABLED(EVENT_DYNAMIC)) {
139                 ret = notify_dynamic(&event);
140                 if (ret)
141                         return log_msg_ret("dyn", ret);
142         }
143
144         return 0;
145 }
146
147 int event_notify_null(enum event_t type)
148 {
149         return event_notify(type, NULL, 0);
150 }
151
152 void event_show_spy_list(void)
153 {
154         struct evspy_info *start =
155                 ll_entry_start(struct evspy_info, evspy_info);
156         const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
157         struct evspy_info *spy;
158         const int size = sizeof(ulong) * 2;
159
160         printf("Seq  %-24s  %*s  %s\n", "Type", size, "Function", "ID");
161         for (spy = start; spy != start + n_ents; spy++) {
162                 printf("%3x  %-3x %-20s  %*p  %s\n", (uint)(spy - start),
163                        spy->type, event_type_name(spy->type), size, spy->func,
164                        event_spy_id(spy));
165         }
166 }
167
168 #if IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)
169 int event_manual_reloc(void)
170 {
171         struct evspy_info *spy, *end;
172
173         spy = ll_entry_start(struct evspy_info, evspy_info);
174         end = ll_entry_end(struct evspy_info, evspy_info);
175         for (; spy < end; spy++)
176                 MANUAL_RELOC(spy->func);
177
178         return 0;
179 }
180 #endif
181
182 #if CONFIG_IS_ENABLED(EVENT_DYNAMIC)
183 static void spy_free(struct event_spy *spy)
184 {
185         list_del(&spy->sibling_node);
186 }
187
188 int event_register(const char *id, enum event_t type, event_handler_t func, void *ctx)
189 {
190         struct event_state *state = gd_event_state();
191         struct event_spy *spy;
192
193         spy = malloc(sizeof(*spy));
194         if (!spy)
195                 return log_msg_ret("alloc", -ENOMEM);
196
197         spy->id = id;
198         spy->type = type;
199         spy->func = func;
200         spy->ctx = ctx;
201         list_add_tail(&spy->sibling_node, &state->spy_head);
202
203         return 0;
204 }
205
206 int event_uninit(void)
207 {
208         struct event_state *state = gd_event_state();
209         struct event_spy *spy, *next;
210
211         list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node)
212                 spy_free(spy);
213
214         return 0;
215 }
216
217 int event_init(void)
218 {
219         struct event_state *state = gd_event_state();
220
221         INIT_LIST_HEAD(&state->spy_head);
222
223         return 0;
224 }
225 #endif /* EVENT_DYNAMIC */
This page took 0.039053 seconds and 4 git commands to generate.