event: Convert misc_init_f() to use events
[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
21 DECLARE_GLOBAL_DATA_PTR;
22
23 #if CONFIG_IS_ENABLED(EVENT_DEBUG)
24 const char *const type_name[] = {
25         "none",
26         "test",
27
28         /* Events related to driver model */
29         "dm_pre_probe",
30         "dm_post_probe",
31         "dm_pre_remove",
32         "dm_post_remove",
33
34         /* init hooks */
35         "misc_init_f",
36 };
37
38 _Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
39 #endif
40
41 static const char *event_type_name(enum event_t type)
42 {
43 #if CONFIG_IS_ENABLED(EVENT_DEBUG)
44         return type_name[type];
45 #else
46         return "(unknown)";
47 #endif
48 }
49
50 static int notify_static(struct event *ev)
51 {
52         struct evspy_info *start =
53                 ll_entry_start(struct evspy_info, evspy_info);
54         const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
55         struct evspy_info *spy;
56
57         for (spy = start; spy != start + n_ents; spy++) {
58                 if (spy->type == ev->type) {
59                         int ret;
60
61                         log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
62                                   event_type_name(ev->type), event_spy_id(spy));
63                         ret = spy->func(NULL, ev);
64
65                         /*
66                          * TODO: Handle various return codes to
67                          *
68                          * - claim an event (no others will see it)
69                          * - return an error from the event
70                          */
71                         if (ret)
72                                 return log_msg_ret("spy", ret);
73                 }
74         }
75
76         return 0;
77 }
78
79 static int notify_dynamic(struct event *ev)
80 {
81         struct event_state *state = gd_event_state();
82         struct event_spy *spy, *next;
83
84         list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node) {
85                 if (spy->type == ev->type) {
86                         int ret;
87
88                         log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
89                                   event_type_name(ev->type), spy->id);
90                         ret = spy->func(spy->ctx, ev);
91
92                         /*
93                          * TODO: Handle various return codes to
94                          *
95                          * - claim an event (no others will see it)
96                          * - return an error from the event
97                          */
98                         if (ret)
99                                 return log_msg_ret("spy", ret);
100                 }
101         }
102
103         return 0;
104 }
105
106 int event_notify(enum event_t type, void *data, int size)
107 {
108         struct event event;
109         int ret;
110
111         event.type = type;
112         if (size > sizeof(event.data))
113                 return log_msg_ret("size", -E2BIG);
114         memcpy(&event.data, data, size);
115
116         ret = notify_static(&event);
117         if (ret)
118                 return log_msg_ret("dyn", ret);
119
120         if (CONFIG_IS_ENABLED(EVENT_DYNAMIC)) {
121                 ret = notify_dynamic(&event);
122                 if (ret)
123                         return log_msg_ret("dyn", ret);
124         }
125
126         return 0;
127 }
128
129 int event_notify_null(enum event_t type)
130 {
131         return event_notify(type, NULL, 0);
132 }
133
134 void event_show_spy_list(void)
135 {
136         struct evspy_info *start =
137                 ll_entry_start(struct evspy_info, evspy_info);
138         const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
139         struct evspy_info *spy;
140         const int size = sizeof(ulong) * 2;
141
142         printf("Seq  %-24s  %*s  %s\n", "Type", size, "Function", "ID");
143         for (spy = start; spy != start + n_ents; spy++) {
144                 printf("%3x  %-3x %-20s  %*p  %s\n", (uint)(spy - start),
145                        spy->type, event_type_name(spy->type), size, spy->func,
146                        event_spy_id(spy));
147         }
148 }
149
150 #if CONFIG_IS_ENABLED(EVENT_DYNAMIC)
151 static void spy_free(struct event_spy *spy)
152 {
153         list_del(&spy->sibling_node);
154 }
155
156 int event_register(const char *id, enum event_t type, event_handler_t func, void *ctx)
157 {
158         struct event_state *state = gd_event_state();
159         struct event_spy *spy;
160
161         if (!CONFIG_IS_ENABLED(EVENT_DYNAMIC))
162                 return -ENOSYS;
163         spy = malloc(sizeof(*spy));
164         if (!spy)
165                 return log_msg_ret("alloc", -ENOMEM);
166
167         spy->id = id;
168         spy->type = type;
169         spy->func = func;
170         spy->ctx = ctx;
171         list_add_tail(&spy->sibling_node, &state->spy_head);
172
173         return 0;
174 }
175
176 int event_uninit(void)
177 {
178         struct event_state *state = gd_event_state();
179         struct event_spy *spy, *next;
180
181         list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node)
182                 spy_free(spy);
183
184         return 0;
185 }
186
187 int event_init(void)
188 {
189         struct event_state *state = gd_event_state();
190
191         INIT_LIST_HEAD(&state->spy_head);
192
193         return 0;
194 }
195 #endif /* EVENT_DYNAMIC */