mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-10-31 12:08:19 +00:00 
			
		
		
		
	Add an event type EVT_MAIN_LOOP that can be used for registering events that need to be run after the platform has been initialised and before the main_loop function is called. Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org> Reviewed-by: Simon Glass <sjg@chromium.org> Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org> Acked-by: Etienne Carriere <etienne.carriere@linaro.org>
		
			
				
	
	
		
			216 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			216 lines
		
	
	
		
			4.4 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",
 | |
| 	"dm_pre_probe",
 | |
| 	"dm_post_probe",
 | |
| 	"dm_pre_remove",
 | |
| 	"dm_post_remove",
 | |
| 
 | |
| 	/* init hooks */
 | |
| 	"misc_init_f",
 | |
| 
 | |
| 	/* fdt hooks */
 | |
| 	"ft_fixup",
 | |
| 
 | |
| 	/* main loop events */
 | |
| 	"main_loop",
 | |
| };
 | |
| 
 | |
| _Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
 | |
| #endif
 | |
| 
 | |
| static 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));
 | |
| 			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("dyn", 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 CONFIG_IS_ENABLED(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 */
 |