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