Simon Glass 91caa3bb89 event: Use an event to replace last_stage_init()
Add a new event which handles this function. Convert existing use of
the function to use the new event instead.

Make sure that EVENT is enabled by affected boards, by selecting it from
the LAST_STAGE_INIT option. For x86, enable it by default since all boards
need it.

For controlcenterdc, inline the get_tpm() function and make sure the event
is not built in SPL.

Signed-off-by: Simon Glass <sjg@chromium.org>
2023-08-31 13:16:55 -04:00

228 lines
4.6 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Events provide a general-purpose way to react to / subscribe to changes
* within U-Boot
*
* Copyright 2021 Google LLC
* Written by Simon Glass <sjg@chromium.org>
*/
#define LOG_CATEGORY LOGC_EVENT
#include <common.h>
#include <event.h>
#include <event_internal.h>
#include <log.h>
#include <linker_lists.h>
#include <malloc.h>
#include <asm/global_data.h>
#include <linux/list.h>
#include <relocate.h>
DECLARE_GLOBAL_DATA_PTR;
#if CONFIG_IS_ENABLED(EVENT_DEBUG)
const char *const type_name[] = {
"none",
"test",
/* Events related to driver model */
"dm_post_init_f",
"dm_pre_probe",
"dm_post_probe",
"dm_pre_remove",
"dm_post_remove",
/* init hooks */
"misc_init_f",
"fsp_init_r",
"last_stage_init",
/* Fpga load hook */
"fpga_load",
/* fdt hooks */
"ft_fixup",
/* main loop events */
"main_loop",
};
_Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
#endif
const char *event_type_name(enum event_t type)
{
#if CONFIG_IS_ENABLED(EVENT_DEBUG)
return type_name[type];
#else
return "(unknown)";
#endif
}
static int notify_static(struct event *ev)
{
struct evspy_info *start =
ll_entry_start(struct evspy_info, evspy_info);
const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
struct evspy_info *spy;
for (spy = start; spy != start + n_ents; spy++) {
if (spy->type == ev->type) {
int ret;
log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
event_type_name(ev->type), event_spy_id(spy));
if (spy->flags & EVSPYF_SIMPLE) {
const struct evspy_info_simple *simple;
simple = (struct evspy_info_simple *)spy;
ret = simple->func();
} else {
ret = spy->func(NULL, ev);
}
/*
* TODO: Handle various return codes to
*
* - claim an event (no others will see it)
* - return an error from the event
*/
if (ret)
return log_msg_ret("spy", ret);
}
}
return 0;
}
static int notify_dynamic(struct event *ev)
{
struct event_state *state = gd_event_state();
struct event_spy *spy, *next;
list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node) {
if (spy->type == ev->type) {
int ret;
log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
event_type_name(ev->type), spy->id);
ret = spy->func(spy->ctx, ev);
/*
* TODO: Handle various return codes to
*
* - claim an event (no others will see it)
* - return an error from the event
*/
if (ret)
return log_msg_ret("spy", ret);
}
}
return 0;
}
int event_notify(enum event_t type, void *data, int size)
{
struct event event;
int ret;
event.type = type;
if (size > sizeof(event.data))
return log_msg_ret("size", -E2BIG);
memcpy(&event.data, data, size);
ret = notify_static(&event);
if (ret)
return log_msg_ret("sta", ret);
if (CONFIG_IS_ENABLED(EVENT_DYNAMIC)) {
ret = notify_dynamic(&event);
if (ret)
return log_msg_ret("dyn", ret);
}
return 0;
}
int event_notify_null(enum event_t type)
{
return event_notify(type, NULL, 0);
}
void event_show_spy_list(void)
{
struct evspy_info *start =
ll_entry_start(struct evspy_info, evspy_info);
const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
struct evspy_info *spy;
const int size = sizeof(ulong) * 2;
printf("Seq %-24s %*s %s\n", "Type", size, "Function", "ID");
for (spy = start; spy != start + n_ents; spy++) {
printf("%3x %-3x %-20s %*p %s\n", (uint)(spy - start),
spy->type, event_type_name(spy->type), size, spy->func,
event_spy_id(spy));
}
}
#if IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)
int event_manual_reloc(void)
{
struct evspy_info *spy, *end;
spy = ll_entry_start(struct evspy_info, evspy_info);
end = ll_entry_end(struct evspy_info, evspy_info);
for (; spy < end; spy++)
MANUAL_RELOC(spy->func);
return 0;
}
#endif
#if CONFIG_IS_ENABLED(EVENT_DYNAMIC)
static void spy_free(struct event_spy *spy)
{
list_del(&spy->sibling_node);
}
int event_register(const char *id, enum event_t type, event_handler_t func, void *ctx)
{
struct event_state *state = gd_event_state();
struct event_spy *spy;
spy = malloc(sizeof(*spy));
if (!spy)
return log_msg_ret("alloc", -ENOMEM);
spy->id = id;
spy->type = type;
spy->func = func;
spy->ctx = ctx;
list_add_tail(&spy->sibling_node, &state->spy_head);
return 0;
}
int event_uninit(void)
{
struct event_state *state = gd_event_state();
struct event_spy *spy, *next;
list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node)
spy_free(spy);
return 0;
}
int event_init(void)
{
struct event_state *state = gd_event_state();
INIT_LIST_HEAD(&state->spy_head);
return 0;
}
#endif /* EVENT_DYNAMIC */