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