@@ -7,10 +7,12 @@
#define LOG_CATEGORY LOGC_EFI
+#include <coroutines.h>
#include <efi_loader.h>
#include <efi_variable.h>
#include <log.h>
#include <asm-generic/unaligned.h>
+#include <stdlib.h>
#define OBJ_LIST_NOT_INITIALIZED 1
@@ -208,6 +210,46 @@ out:
return -1;
}
+#if CONFIG_IS_ENABLED(COROUTINES)
+
+static void efi_disks_register_co(void)
+{
+ efi_status_t ret;
+
+ if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED)
+ goto out;
+
+ /*
+ * Probe block devices to find the ESP.
+ * efi_disks_register() must be called before efi_init_variables().
+ */
+ ret = efi_disks_register();
+ if (ret != EFI_SUCCESS)
+ efi_obj_list_initialized = ret;
+out:
+ co_exit();
+}
+
+static void efi_tcg2_register_co(void)
+{
+ efi_status_t ret = EFI_SUCCESS;
+
+ if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED)
+ goto out;
+
+ if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {
+ ret = efi_tcg2_register();
+ if (ret != EFI_SUCCESS)
+ efi_obj_list_initialized = ret;
+ }
+out:
+ co_exit();
+}
+
+extern int udelay_yield;
+
+#endif /* COROUTINES */
+
/**
* efi_init_obj_list() - Initialize and populate EFI object list
*
@@ -216,6 +258,12 @@ out:
efi_status_t efi_init_obj_list(void)
{
efi_status_t ret = EFI_SUCCESS;
+#if CONFIG_IS_ENABLED(COROUTINES)
+ struct co_stack *stk = NULL;
+ struct co *main_co = NULL;
+ struct co *co1 = NULL;
+ struct co *co2 = NULL;
+#endif
/* Initialize once only */
if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED)
@@ -224,6 +272,53 @@ efi_status_t efi_init_obj_list(void)
/* Set up console modes */
efi_setup_console_size();
+#if CONFIG_IS_ENABLED(COROUTINES)
+ main_co = co_create(NULL, NULL, 0, NULL, NULL);
+ if (!main_co) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+
+ stk = co_stack_new(8192);
+ if (!stk) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+
+ co1 = co_create(main_co, stk, 0, efi_disks_register_co, NULL);
+ if (!co1) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+
+ co2 = co_create(main_co, stk, 0, efi_tcg2_register_co, NULL);
+ if (!co2) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+
+ udelay_yield = 0xCAFEDECA;
+ do {
+ if (!co1->done)
+ co_resume(co1);
+ if (!co2->done)
+ co_resume(co2);
+ } while (!(co1->done && co2->done));
+ udelay_yield = 0;
+
+ co_stack_destroy(stk);
+ co_destroy(main_co);
+ co_destroy(co1);
+ co_destroy(co2);
+ stk = NULL;
+ main_co = co1 = co2 = NULL;
+
+ if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED) {
+ /* Some kind of error was saved by a coroutine */
+ ret = efi_obj_list_initialized;
+ goto out;
+ }
+#else
/*
* Probe block devices to find the ESP.
* efi_disks_register() must be called before efi_init_variables().
@@ -232,6 +327,13 @@ efi_status_t efi_init_obj_list(void)
if (ret != EFI_SUCCESS)
goto out;
+ if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {
+ ret = efi_tcg2_register();
+ if (ret != EFI_SUCCESS)
+ efi_obj_list_initialized = ret;
+ }
+#endif
+
/* Initialize variable services */
ret = efi_init_variables();
if (ret != EFI_SUCCESS)
@@ -272,10 +374,6 @@ efi_status_t efi_init_obj_list(void)
}
if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {
- ret = efi_tcg2_register();
- if (ret != EFI_SUCCESS)
- goto out;
-
ret = efi_tcg2_do_initial_measurement();
if (ret == EFI_SECURITY_VIOLATION)
goto out;
@@ -350,6 +448,13 @@ efi_status_t efi_init_obj_list(void)
!IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY))
ret = efi_launch_capsules();
out:
+#if CONFIG_IS_ENABLED(COROUTINES)
+ co_stack_destroy(stk);
+ co_destroy(main_co);
+ co_destroy(co1);
+ co_destroy(co2);
efi_obj_list_initialized = ret;
+#endif
+
return ret;
}
@@ -17,6 +17,7 @@
#include <asm/global_data.h>
#include <asm/io.h>
#include <linux/delay.h>
+#include <coroutines.h>
#ifndef CFG_WD_PERIOD
# define CFG_WD_PERIOD (10 * 1000 * 1000) /* 10 seconds default */
@@ -190,6 +191,8 @@ void __weak __udelay(unsigned long usec)
/* ------------------------------------------------------------------------- */
+int udelay_yield;
+
void udelay(unsigned long usec)
{
ulong kv;
@@ -197,7 +200,16 @@ void udelay(unsigned long usec)
do {
schedule();
kv = usec > CFG_WD_PERIOD ? CFG_WD_PERIOD : usec;
- __udelay(kv);
+ if (CONFIG_IS_ENABLED(COROUTINES) &&
+ udelay_yield == 0xCAFEDECA) {
+ ulong t0 = timer_get_us();
+ do {
+ co_yield();
+ __udelay(10);
+ } while (timer_get_us() < t0 + kv);
+ } else {
+ __udelay(kv);
+ }
usec -= kv;
} while(usec);
}
When COROUTINES is enabled, schedule efi_disks_register() and efi_tcg2_register() as two coroutines in efi_init_obj_list() instead of invoking them sequentially. The voluntary yield point is introduced inside udelay() which is called frequently as a result of each function polling the hardware. This allows the two coroutines to make progress simultaneously and reduce the wall clock time required by efi_init_obj_list(). Tested on Kria KV260 with a microSD card inserted with the "printenv -e" command. With COROUTINES disabled, efi_init_obj_list() completes in 2821 ms on average (2825, 2822, 2817). With COROUTINES enabled, it takes 2265 ms (2262, 2260, 2272). That is a reduction of 556 ms which is not bad at all considering that measured separately, efi_tcg2_register() takes ~825 ms and efi_disks_register() needs ~600 ms, so assuming they would overlap perfectly one can expect a 600 ms improvement at best. The code size penalty for this improvement is 1340 bytes. Signed-off-by: Jerome Forissier <jerome.forissier@linaro.org> --- lib/efi_loader/efi_setup.c | 113 +++++++++++++++++++++++++++++++++++-- lib/time.c | 14 ++++- 2 files changed, 122 insertions(+), 5 deletions(-)