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