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