From patchwork Tue Jan 28 10:19:15 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerome Forissier X-Patchwork-Id: 860375 Delivered-To: patch@linaro.org Received: by 2002:a5d:6b8c:0:b0:385:e875:8a9e with SMTP id n12csp278970wrx; Tue, 28 Jan 2025 02:20:25 -0800 (PST) X-Forwarded-Encrypted: i=2; AJvYcCXL0IydfRX81+PP11aIGw+JelQbeHXBpfYyBK0z2jcplQIVmdrfvyD4Mlj9Bc3991D7GAsEGQ==@linaro.org X-Google-Smtp-Source: AGHT+IEMv4X+jVOo0OIJ6SXIF7mHeKNMgsJtRlNvyGv2Gj2erxenjTAopeymJ5FnQlKcrvTl+mPk X-Received: by 2002:a17:907:d1b:b0:ab2:dc73:34bd with SMTP id a640c23a62f3a-ab38b3cce0dmr3821482366b.48.1738059622675; Tue, 28 Jan 2025 02:20:22 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1738059622; cv=none; d=google.com; s=arc-20240605; b=gEPhDsCn2C9ZXroF6ohfYxryLbOAcbgd1f5yRiAscGu2ybTuvotU8q58E536XqUo3h WTlsmzGC6VTqiWDck6mKlF4OKUi1+oOWI9y3aBFUM4en/lWVvaIJfy8fdQ3mgZwDpm9R xOpX3yLLggpjH3sYMfpRE6ilpcyslBgcgAU3fIzTtDZ5wb+4OZWlASGjtg9KlTiEnIsI JM4Zys3m5ebxPSy+aurHKM7Osf80FqEccWdEZYLfBp7Pgf7vuB54OHHFuzetVtQmehiw bi2PoOyC4lscIk/687fjPIL4cl6iLQp4+v9GzKwWLQITIPNjpH52A4slmrg3/o2dtz51 pbxQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=l19PuP4ODUrTR/2AYyzc8r/irD4KouXnvzx9dslITWI=; fh=vyy5tkMwCRzsENjYcxU0WRUaA2LMsk43+vm7mtFMZdc=; b=I4xXcadD72VdkfSNt/Zjhxr21L0Om+ri4kGswnjqar1ufrSgB21Nu/NyMWtK2GUg7b b7NueiXRR5J570txtdTP4L2Ek5lrOmRdvySR1a5PyeVwQXmu04/X6tzgL0SBYY1kdnyh //vaZDwqRBxgVrpwPGKdeAYDivIWB7SwbqDNBGbS8kFLWBVMwWyTqW2VJPqwvk+0RD9X 8+cxHEmQCW+e8ay4cW2lT4W+roJAJ9XJD6CdH0+WONl7FK1eBcdrXXdSxlqjSDbet5Q9 gKSsKPBJJ2ne4UA2aYMBXPcumHznLkqzIbQc4vvBvqQk4YogAaxwcUbAFIQUnOpMoZyP lM4w==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=NU5i8SgP; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org; dara=neutral header.i=@linaro.org Return-Path: Received: from phobos.denx.de (phobos.denx.de. [2a01:238:438b:c500:173d:9f52:ddab:ee01]) by mx.google.com with ESMTPS id a640c23a62f3a-ab67626f751si711826166b.570.2025.01.28.02.20.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 28 Jan 2025 02:20:22 -0800 (PST) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=NU5i8SgP; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org; dara=neutral header.i=@linaro.org Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 56D2881B4B; Tue, 28 Jan 2025 11:20:11 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="NU5i8SgP"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 783C381DA8; Tue, 28 Jan 2025 11:20:09 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-wm1-x344.google.com (mail-wm1-x344.google.com [IPv6:2a00:1450:4864:20::344]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id EBAE981D42 for ; Tue, 28 Jan 2025 11:20:06 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=jerome.forissier@linaro.org Received: by mail-wm1-x344.google.com with SMTP id 5b1f17b1804b1-43621d27adeso36193905e9.2 for ; Tue, 28 Jan 2025 02:20:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1738059606; x=1738664406; darn=lists.denx.de; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=l19PuP4ODUrTR/2AYyzc8r/irD4KouXnvzx9dslITWI=; b=NU5i8SgPH+xTgQgNvCmOPbZ+7TN4yA88/MSvLKRgRz9deJLtoLwJvLUFxQUm2Bh+Z/ D5JJMxw+afYgjsPr2k5IsuWbDiwhZtGpM+FhXT4QpWX+PZU4JMM4yWoV1SeQ9A9YuRKo D4uUgpbOkIAdR/F4fAg8A2oM4jeGGJP6zZQgSF+CwS1K9K8G9aIXUeumlv+UgLwdxYqS FqxAj6yG8QTExKdE3rqGwtNsS6jttDGFNZ0XTP9QsHWxCP6bhlinsseTWv0opWis51V0 wJ7c6gjPy8mh2OFzzfX+YQOJ6LMydwoijKEj4V6XZTtnjwgA/8Aw/YIZEaNgsnWNRe9Z hg4Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738059606; x=1738664406; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=l19PuP4ODUrTR/2AYyzc8r/irD4KouXnvzx9dslITWI=; b=tZ/tZntM9q+CZrSj2i7AQWE9ad41a7O6tkv8mS/Y7s/UG6yVrKV02X23or+57dObA5 6gEKoGYZaIKHK7YKn5M4T+FFFc6kcoquYEpWjQeSii9ilGg+aOnOyrQZeJgWGUyzBjfz mc3jpjtKuEX+QkBcVDdTSt8dub9ZBvgsU879Zd/5dXXYwcpWizqskygftjn/UF72Ln9y ek2aFMfhU2BYZQvUch4Pnr+RHhD4WwHupRJ5ie3wml90uqshAZY5O97nM1vfs8qqzSQr jyUfDJ6tHwgZ6FIwjdo/h2bl6w6Z/oYGWtA7jU5hpQqYlbPO/AsReoZdAlFUV0ryeHSI JlQA== X-Gm-Message-State: AOJu0YxSJh8oenzE8HTUqz6pczzq/URtjKCdsM8pNeZS7Rej+//dUZTL jRvPX4aw/i0t6dseDT7YuwDVii07kZeCOUdDeQkOF8L1SfP5L8LhLCDQ33PtBnyPPWfk7PjCic5 5MhKAV2Dj X-Gm-Gg: ASbGncv3s7+thtLFfA3ww47JvwbvpTVYnCMY0mLQZHjegmyR6JJ+9KiwTJ6UBlWGU8d aFlob37BEBFlXAaHHwfnFkQ0C7K0/3pW0khGRo+ozwzU2oMakL8VNliHZy1IPQFsDw/xd479quK gJ6cQ9mMZJ9fcp/zYpJl9EtnoWO8MZ8595VByBssH4YozfGqJlvX086FsK10NgerMA+kxnB/0gc uQJNXeonwXnfJO+CqxmTR1I4uZEyHiLhO6u3Qf4u4U4DtHl7oFKwZGdDv8Db8gHFL/MLdl7GmR8 GEnvmbsr+tNYfnR34L3fvaM= X-Received: by 2002:a05:600c:a09:b0:435:9ed3:5688 with SMTP id 5b1f17b1804b1-438913f86dcmr415396575e9.18.1738059606109; Tue, 28 Jan 2025 02:20:06 -0800 (PST) Received: from builder.. ([2a01:e0a:3cb:7bb0:45e:43e2:ed61:42fe]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-438bd4b9977sm164651245e9.25.2025.01.28.02.20.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 28 Jan 2025 02:20:05 -0800 (PST) From: Jerome Forissier To: u-boot@lists.denx.de Cc: Ilias Apalodimas , Jerome Forissier , Tom Rini , Simon Glass , Patrick Rudolph , Sughosh Ganu , Michal Simek , Raymond Mao , Heinrich Schuchardt Subject: [RFC PATCH v2 1/3] Introduce coroutines framework Date: Tue, 28 Jan 2025 11:19:15 +0100 Message-ID: <912af13c205a31080cc61d40bec29d7402185d6e.1738059345.git.jerome.forissier@linaro.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.8 at phobos.denx.de X-Virus-Status: Clean Adds the COROUTINES Kconfig symbol which introduces a new internal API for coroutines support. As explained in the Kconfig file, this is meant to provide some kind of cooperative multi-tasking with the goal to improve performance by overlapping lengthy operations. The API as well as the implementation is very much inspired from libaco [1]. The reference implementation is simplified to remove all things not needed in U-Boot, the coding style is updated, and the aco_ prefix is replaced by co_. I believe the stack handling could be simplified: the stack of the main coroutine could probably probably be used by the secondary coroutines instead of allocating a new stack dynamically. Only i386, x86_64 and aarch64 are supported at the moment. Other architectures need to provide a _co_switch() function in assembly. Only aarch64 has been tested. [1] https://github.com/hnes/libaco/ Signed-off-by: Jerome Forissier --- arch/arm/cpu/armv8/Makefile | 1 + arch/arm/cpu/armv8/co_switch.S | 36 +++++++ include/coroutines.h | 130 ++++++++++++++++++++++++++ lib/Kconfig | 10 ++ lib/Makefile | 2 + lib/coroutines.c | 165 +++++++++++++++++++++++++++++++++ 6 files changed, 344 insertions(+) create mode 100644 arch/arm/cpu/armv8/co_switch.S create mode 100644 include/coroutines.h create mode 100644 lib/coroutines.c diff --git a/arch/arm/cpu/armv8/Makefile b/arch/arm/cpu/armv8/Makefile index 2e71ff2dc97..6d07b6aa9f9 100644 --- a/arch/arm/cpu/armv8/Makefile +++ b/arch/arm/cpu/armv8/Makefile @@ -46,3 +46,4 @@ obj-$(CONFIG_TARGET_BCMNS3) += bcmns3/ obj-$(CONFIG_XEN) += xen/ obj-$(CONFIG_ARMV8_CE_SHA1) += sha1_ce_glue.o sha1_ce_core.o obj-$(CONFIG_ARMV8_CE_SHA256) += sha256_ce_glue.o sha256_ce_core.o +obj-$(CONFIG_COROUTINES) += co_switch.o diff --git a/arch/arm/cpu/armv8/co_switch.S b/arch/arm/cpu/armv8/co_switch.S new file mode 100644 index 00000000000..4405e89ec56 --- /dev/null +++ b/arch/arm/cpu/armv8/co_switch.S @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* void _co_switch(struct uco *from_co, struct uco *to_co); */ +.text +.globl _co_switch +.type _co_switch, @function +_co_switch: + // x0: from_co + // x1: to_co + // from_co and to_co layout: { pc, sp, x19-x29 } + + // Save context to from_co (x0) + // AAPCS64 says "A subroutine invocation must preserve the contents of the + // registers r19-r29 and SP" + adr x2, 1f // pc we should use to resume after this function + mov x3, sp + stp x2, x3, [x0, #0] // pc, sp + stp x19, x20, [x0, #16] + stp x21, x22, [x0, #32] + stp x23, x24, [x0, #48] + stp x25, x26, [x0, #64] + stp x27, x28, [x0, #80] + stp x29, x30, [x0, #96] + + // Load new context from to_co (x1) + ldp x2, x3, [x1, #0] // pc, sp + ldp x19, x20, [x1, #16] + ldp x21, x22, [x1, #32] + ldp x23, x24, [x1, #48] + ldp x25, x26, [x1, #64] + ldp x27, x28, [x1, #80] + ldp x29, x30, [x1, #96] + mov sp, x3 + br x2 + +1: // Return to the caller + ret diff --git a/include/coroutines.h b/include/coroutines.h new file mode 100644 index 00000000000..b85b656127c --- /dev/null +++ b/include/coroutines.h @@ -0,0 +1,130 @@ +/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ +/* + * Copyright 2018 Sen Han <00hnes@gmail.com> + * Copyright 2025 Linaro Limited + */ + +#ifndef _COROUTINES_H_ +#define _COROUTINES_H_ + +#ifndef CONFIG_COROUTINES + +static inline void co_yield(void) {} +static inline void co_exit(void) {} + +#else + +#ifdef __UBOOT__ +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#ifdef __aarch64__ +#define CO_REG_IDX_RETADDR 0 +#define CO_REG_IDX_SP 1 +#else +#error Architecture no supported +#endif + +struct co_save_stack { + void* ptr; + size_t sz; + size_t valid_sz; + size_t max_cpsz; /* max copy size in bytes */ +}; + +struct co_stack { + void *ptr; + size_t sz; + void *align_highptr; + void *align_retptr; + size_t align_validsz; + size_t align_limit; + struct co *owner; + void *real_ptr; + size_t real_sz; +}; + +struct co { + /* CPU state: callee-saved registers plus SP and PC */ + void *reg[14]; // pc, sp, x19-x29, x30 (lr) + + struct co *main_co; + void *arg; + bool done; + + void (*fp)(void); + + struct co_save_stack save_stack; + struct co_stack *stack; +}; + +extern struct co *current_co; + +static inline struct co *co_get_co(void) +{ + return current_co; +} + +static inline void *co_get_arg(void) +{ + return co_get_co()->arg; +} + +struct co_stack *co_stack_new(size_t sz); + +void co_stack_destroy(struct co_stack *s); + +struct co *co_create(struct co *main_co, + struct co_stack *stack, + size_t save_stack_sz, void (*fp)(void), + void *arg); + +void co_resume(struct co *resume_co); + +void co_destroy(struct co *co); + +void *_co_switch(struct co *from_co, struct co *to_co); + +static inline void _co_yield_to_main_co(struct co *yield_co) +{ + assert(yield_co); + assert(yield_co->main_co); + _co_switch(yield_co, yield_co->main_co); +} + +static inline void co_yield(void) +{ + if (current_co) + _co_yield_to_main_co(current_co); +} + +static inline bool co_is_main_co(struct co *co) +{ + return !co->main_co; +} + +static inline void co_exit(void) +{ + struct co *co = co_get_co(); + + if (!co) + return; + co->done = true; + assert(co->stack->owner == co); + co->stack->owner = NULL; + co->stack->align_validsz = 0; + _co_yield_to_main_co(co); + assert(false); +} + +#endif /* CONFIG_COROUTINES */ +#endif /* _COROUTINES_H_ */ diff --git a/lib/Kconfig b/lib/Kconfig index 8f1a96d98c4..b6c1380b927 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -1226,6 +1226,16 @@ config PHANDLE_CHECK_SEQ enable this config option to distinguish them using phandles in fdtdec_get_alias_seq() function. +config COROUTINES + bool "Enable coroutine support" + help + Coroutines allow to implement a simple form of cooperative + multi-tasking. The main thread of execution registers one or + more functions as coroutine entry points, then it schedules one + of them. At any point the scheduled coroutine may yield, that is, + suspend its execution and return back to the main thread. At this + point another coroutine may be scheduled and so on until all the + registered coroutines are done. endmenu source "lib/fwu_updates/Kconfig" diff --git a/lib/Makefile b/lib/Makefile index 5cb3278d2ef..7b809151f5a 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -159,6 +159,8 @@ obj-$(CONFIG_LIB_ELF) += elf.o obj-$(CONFIG_$(PHASE_)SEMIHOSTING) += semihosting.o +obj-$(CONFIG_COROUTINES) += coroutines.o + # # Build a fast OID lookup registry from include/linux/oid_registry.h # diff --git a/lib/coroutines.c b/lib/coroutines.c new file mode 100644 index 00000000000..20c5aba5510 --- /dev/null +++ b/lib/coroutines.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + +// Copyright 2018 Sen Han <00hnes@gmail.com> +// Copyright 2025 Linaro Limited + +#include +#include +#include + + +/* Current co-routine */ +struct co *current_co; + +struct co_stack *co_stack_new(size_t sz) +{ + struct co_stack *p = calloc(1, sizeof(*p)); + uintptr_t u_p; + + if (!p) + return NULL; + + if (sz < 4096) + sz = 4096; + + p->sz = sz; + p->ptr = malloc(sz); + if (!p->ptr) { + free(p); + return NULL; + } + + p->owner = NULL; + u_p = (uintptr_t)(p->sz - (sizeof(void*) << 1) + (uintptr_t)p->ptr); + u_p = (u_p >> 4) << 4; + p->align_highptr = (void*)u_p; + p->align_retptr = (void*)(u_p - sizeof(void*)); + assert(p->sz > (16 + (sizeof(void*) << 1) + sizeof(void*))); + p->align_limit = p->sz - 16 - (sizeof(void*) << 1); + + return p; +} + +void co_stack_destroy(struct co_stack *s){ + if (!s) + return; + free(s->ptr); + free(s); +} + +struct co *co_create(struct co *main_co, + struct co_stack *stack, + size_t save_stack_sz, + void (*fp)(void), void *arg) +{ + struct co *p = malloc(sizeof(*p)); + assert(p); + memset(p, 0, sizeof(*p)); + + if (main_co) { + assert(stack); + p->stack = stack; + p->reg[CO_REG_IDX_RETADDR] = (void *)fp; + // FIXME original code uses align_retptr; causes a crash + p->reg[CO_REG_IDX_SP] = p->stack->align_highptr; + p->main_co = main_co; + p->arg = arg; + p->fp = fp; + if (!save_stack_sz) + save_stack_sz = 64; + p->save_stack.ptr = malloc(save_stack_sz); + assert(p->save_stack.ptr); + p->save_stack.sz = save_stack_sz; + p->save_stack.valid_sz = 0; + } else { + p->main_co = NULL; + p->arg = arg; + p->fp = fp; + p->stack = NULL; + p->save_stack.ptr = NULL; + } + return p; +} + +static void grab_stack(struct co *resume_co) +{ + struct co *owner_co = resume_co->stack->owner; + + if (owner_co) { + assert(owner_co->stack == resume_co->stack); + assert((uintptr_t)(owner_co->stack->align_retptr) >= + (uintptr_t)(owner_co->reg[CO_REG_IDX_SP])); + assert((uintptr_t)owner_co->stack->align_highptr - + (uintptr_t)owner_co->stack->align_limit + <= (uintptr_t)owner_co->reg[CO_REG_IDX_SP]); + owner_co->save_stack.valid_sz = + (uintptr_t)owner_co->stack->align_retptr - + (uintptr_t)owner_co->reg[CO_REG_IDX_SP]; + if (owner_co->save_stack.sz < owner_co->save_stack.valid_sz) { + free(owner_co->save_stack.ptr); + owner_co->save_stack.ptr = NULL; + do { + owner_co->save_stack.sz <<= 1; + assert(owner_co->save_stack.sz > 0); + } while (owner_co->save_stack.sz < + owner_co->save_stack.valid_sz); + owner_co->save_stack.ptr = + malloc(owner_co->save_stack.sz); + assert(owner_co->save_stack.ptr); + } + if (owner_co->save_stack.valid_sz > 0) + memcpy(owner_co->save_stack.ptr, + owner_co->reg[CO_REG_IDX_SP], + owner_co->save_stack.valid_sz); + if (owner_co->save_stack.valid_sz > + owner_co->save_stack.max_cpsz) + owner_co->save_stack.max_cpsz = + owner_co->save_stack.valid_sz; + owner_co->stack->owner = NULL; + owner_co->stack->align_validsz = 0; + } + assert(!resume_co->stack->owner); + assert(resume_co->save_stack.valid_sz <= + resume_co->stack->align_limit - sizeof(void *)); + if (resume_co->save_stack.valid_sz > 0) + memcpy((void*) + (uintptr_t)(resume_co->stack->align_retptr) - + resume_co->save_stack.valid_sz, + resume_co->save_stack.ptr, + resume_co->save_stack.valid_sz); + if (resume_co->save_stack.valid_sz > resume_co->save_stack.max_cpsz) + resume_co->save_stack.max_cpsz = resume_co->save_stack.valid_sz; + resume_co->stack->align_validsz = + resume_co->save_stack.valid_sz + sizeof(void *); + resume_co->stack->owner = resume_co; +} + +void co_resume(struct co *resume_co) +{ + assert(resume_co && resume_co->main_co && !resume_co->done); + + if (resume_co->stack->owner != resume_co) + grab_stack(resume_co); + + current_co = resume_co; + _co_switch(resume_co->main_co, resume_co); + current_co = resume_co->main_co; +} + +void co_destroy(struct co *co){ + if (!co) + return; + + if(co_is_main_co(co)){ + free(co); + current_co = NULL; + } else { + if(co->stack->owner == co){ + co->stack->owner = NULL; + co->stack->align_validsz = 0; + } + free(co->save_stack.ptr); + co->save_stack.ptr = NULL; + free(co); + } +} From patchwork Tue Jan 28 10:19:16 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerome Forissier X-Patchwork-Id: 860377 Delivered-To: patch@linaro.org Received: by 2002:a5d:6b8c:0:b0:385:e875:8a9e with SMTP id n12csp281895wrx; Tue, 28 Jan 2025 02:30:43 -0800 (PST) X-Forwarded-Encrypted: i=2; AJvYcCU1NvMoxuwIfn1Nv3kfxG56ex1EQ6sL0Wp6W+jEZPrBh64WDbqObQ80+jXqjYUhmchY3YR0vA==@linaro.org X-Google-Smtp-Source: AGHT+IF6IYwP2fr06/augRlOt5IRuCyA6qhlK2SaYzTeiYg9yiSUbmNtd9B8jd4B3LcPpR86GisL X-Received: by 2002:a17:907:969f:b0:aa6:762e:8c20 with SMTP id a640c23a62f3a-ab38b37cf93mr4581580966b.43.1738060243246; Tue, 28 Jan 2025 02:30:43 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1738060243; cv=none; d=google.com; s=arc-20240605; b=H20LTudYwNteYp5OiMvvlvjrM7yKiQKF9dAvpVlX3MiBbpR7i1Y5dtnS+4tKtsX1GE MFTcjl3EhSlLL5t+udg7/uAXbGzQEawQGEOq/2wTLqlzkz5zn/wOmBT+oT49JFIcC89s TVvkdXhinqUxq0xuWm9Z6i+TFN7PuFqbE0hiol/A+mRMJPLwDRpSUepWI1FPz02J56++ qKx9tY5/o8Itx8uSdSLKf6i9RV9RzCk3JtAAF7L6t7phT5O0Rz6YYEKR9rKbAtV6w+FD V9fI0fw4/CLeDV0VpJ0phDDTUYfiGhgnzBPG3XNABczQ3I9QOY7iufeFDIga8AIErnoU I1pQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=BqWBxBeSBN85uoyU0epbXFnDKcvIpLM2onBGrSfc4vg=; fh=Nk/iIugUz6rZzcw+U4zB1tZpnMlZYNJpKOQcuMdjy8o=; b=ZkZuSC1sQ1rQfxybSwebiQqgHnPiUEl1O4ecRrlKb4thez1gGfxIrhGJf1TnoF26qW GA8ksVkTGy472/ZIphFM8OsZKHRTOhMD9dE1zcatyZ4eCArZz1iGSGTDy1O6kjSC5hH9 d1ofdAmT/t/DrYAQz9nUy6AJWQGbgvyhmuLe+HyUkbsM5yrePgsSJ7WNORIEMArO/6C+ zNwQ4KKr01v3oOeP+Nbpow0cR7AEP7faeohXxLvlJYbupLfm7h1fv601Od7NkyTpz1Fc kioyt9jPThdtp5oHMKS9HWQxwnzg5zvzqgWIT3OrUQMWeKDHRo4WVQlE5Gyfhhw9RK+N Mi4g==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=vehJIa2e; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org; dara=neutral header.i=@linaro.org Return-Path: Received: from phobos.denx.de (phobos.denx.de. [2a01:238:438b:c500:173d:9f52:ddab:ee01]) by mx.google.com with ESMTPS id a640c23a62f3a-ab6762ab446si721183466b.737.2025.01.28.02.30.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 28 Jan 2025 02:30:43 -0800 (PST) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=vehJIa2e; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org; dara=neutral header.i=@linaro.org Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id A330081DA8; Tue, 28 Jan 2025 11:20:11 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="vehJIa2e"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 74B3F81D42; Tue, 28 Jan 2025 11:20:10 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-wm1-x330.google.com (mail-wm1-x330.google.com [IPv6:2a00:1450:4864:20::330]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id B6A0781D5A for ; Tue, 28 Jan 2025 11:20:07 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=jerome.forissier@linaro.org Received: by mail-wm1-x330.google.com with SMTP id 5b1f17b1804b1-43690d4605dso36335555e9.0 for ; Tue, 28 Jan 2025 02:20:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1738059607; x=1738664407; darn=lists.denx.de; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=BqWBxBeSBN85uoyU0epbXFnDKcvIpLM2onBGrSfc4vg=; b=vehJIa2eEzlk1fnQMCYu+iQhmYQH9Je4igXoDWQAXZ4n2gOunoZaGQphO8FoG10UWu Ngj91iDbINccGT0rnxO/5NEQOlitd5maXaCGi1sg7HWuRvYtp386g2eJKYQXK5Gfyffa rftnMLSaNJFVMgtvYWO1RH4o2Tw9m4mwQMyEBHvMIhTyovHy9wi3HOCqYo9RrBnNGs91 PMGD45QYftjW0fBOodFdz7XRif/Aa0abwf9dPPMjtNVc8JQ58ntW57BzcYU0CWoDPxov GT7TSlmGVsfwz4sdR2aRVU8WzgS8KNCgFwfUDQrnrg1MoE0jFzLfjvxWr7h+O5F/wM1x tVnA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738059607; x=1738664407; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=BqWBxBeSBN85uoyU0epbXFnDKcvIpLM2onBGrSfc4vg=; b=OTltHAG10kVeifjZ+Swb09KCmXQpjUXWAASX9eUpMpgyoyO7QryJVJgJjF9Sk2KrKW uD+FmsEDetZkdfPTiPCygXauwiEa6DRA+2VaIImzDNcwVGqIHLJnAeki5NOcnvHI5/1x JREYIKrPtRhOVt/nXjrp4w43ggeS1EhMbtgquSUNUjAhInF4L4C44SZuc8wCBnwdnYWO NVYiLdRIhKu2EVqxCBQAOpzu1QkCEHH6ELET2qfk0YHU2CeL1ImWnwFhH9arHacIPOEZ uS6o4D1PRABXQcOIyf+KXtcg5om1eQI4PfrcAhIX1Jpdfe2vb3dSGLRxQGYMs3zsSRH7 SVrQ== X-Gm-Message-State: AOJu0YzHQEiY/yepSnSPEFyPkq0EzIw1F3vQMXcRhcRi7G+P0Sjjm2jh Xx6crlBTlqYClEoEOSCTgtn1ar/jX+mtgXl9CJN/nd8BdZHg7qypmSR/TdQT0pOhrnXPQgSUOTV 40/TX6Q== X-Gm-Gg: ASbGncsSdJZjHbFJUDmsnYY+LkE982zskDHvqJln3U25VE7HEWY47sOo9QQBdbyiUIy idOpQP1gCBIMm+/kTpeoeDjeMJ0pUIuaWqMfC49EcgxZR5ULFQFLlGxWQMfyMZ/oXqrXuaO5q9t VqZd3Mx2na3ASCVz9Ob351vbjO0J61jqLIVc1b4jZxoRYDW9dwCJr7UBUGpgBXo9/8JVldQ8UBq 66z8Knfi2Ch8VW9rZP8MQ/faOtWJVRbLE3LV3sguYlnTDUbU8UuZCgdw452MPl0Mj9236jyfIvk xQWA17nSbmTAk9s43Pt2ZVow2/vjqqwYAQ== X-Received: by 2002:a05:600c:3149:b0:436:5fc9:30ba with SMTP id 5b1f17b1804b1-43891441f57mr423818165e9.29.1738059606927; Tue, 28 Jan 2025 02:20:06 -0800 (PST) Received: from builder.. ([2a01:e0a:3cb:7bb0:45e:43e2:ed61:42fe]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-438bd4b9977sm164651245e9.25.2025.01.28.02.20.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 28 Jan 2025 02:20:06 -0800 (PST) From: Jerome Forissier To: u-boot@lists.denx.de Cc: Ilias Apalodimas , Jerome Forissier , Heinrich Schuchardt , Tom Rini , Simon Glass Subject: [RFC PATCH v2 2/3] efi_loader: optimize efi_init_obj_list() with coroutines Date: Tue, 28 Jan 2025 11:19:16 +0100 Message-ID: X-Mailer: git-send-email 2.43.0 In-Reply-To: References: MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.8 at phobos.denx.de X-Virus-Status: Clean 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 --- lib/efi_loader/efi_setup.c | 113 +++++++++++++++++++++++++++++++++++-- lib/time.c | 14 ++++- 2 files changed, 122 insertions(+), 5 deletions(-) diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index aa59bc7779d..94160f4bd86 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -7,10 +7,12 @@ #define LOG_CATEGORY LOGC_EFI +#include #include #include #include #include +#include #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; } diff --git a/lib/time.c b/lib/time.c index d88edafb196..c11288102fe 100644 --- a/lib/time.c +++ b/lib/time.c @@ -17,6 +17,7 @@ #include #include #include +#include #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); } From patchwork Tue Jan 28 10:19:17 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerome Forissier X-Patchwork-Id: 860376 Delivered-To: patch@linaro.org Received: by 2002:a5d:6b8c:0:b0:385:e875:8a9e with SMTP id n12csp279072wrx; Tue, 28 Jan 2025 02:20:42 -0800 (PST) X-Forwarded-Encrypted: i=2; AJvYcCUDCYUIfrWMsukwYFXpA9O0oeLvtwXfEG2sVkr5Rmd17c1Nji+qnOdHigJ426vHFTI/AqU6RQ==@linaro.org X-Google-Smtp-Source: AGHT+IE1caddo+v0hfEZsU8tfIT778dEVj0KXIfhp1L4YJ8+ns5uvNuRsi9Yw216lvReDbpmlYrL X-Received: by 2002:a17:907:3f23:b0:ab3:f88:b54e with SMTP id a640c23a62f3a-ab38b2e71e0mr4128650466b.31.1738059642723; Tue, 28 Jan 2025 02:20:42 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1738059642; cv=none; d=google.com; s=arc-20240605; b=QrWLburfJUuCTpctEqzARbcOHn3aSk6SruLAdYi2m+jl6y4H8dCKXgo9oIb+ptoqW+ 5QUECy6kE2cjGGkRgULG7XusJA5hpL8WXlWVna8KvZhSREKIJ/3ah4BjRSv4v3+OndpD 0rNSWw7zBXYHU31DqzzExtb/iI39WdPMWG/mbeINhNUU/RlbbH6DKB+ppwvMA4Ubsd7a f4GwgZ3n37cGoBk1E2GYVrY+FipPz57SU2eEn9bOxajLw7wHUAPTU0ppnm2Z8HMKDyPC r3kbytjo/3Vuo1+40VhVF9zfMpuQmoAjYtrgptBGmHaqVw0DPmpxYqs+iCMCkPu6JqYZ mlHQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=fASuFHKqVp07Z9xdr3bFH4y39Xbm1J0R9QOhNN8bHWA=; fh=7m7KVwLEJqxnAoXP8Sj3ToP+pYgLPIs3VM3sOSqK4kg=; b=LaVDSTsnDTsaDSx4kr64fzjnVbiavnu9g8CHLsXQeKBBMQwrs48qyAgifsNMlYyxB+ BquJEBzgYq4fCH7PkgQ7ERn1Dqu+Zi4b/IKue6f5dKxuCM4p2CY/frFfSlphskBO/MyD jGoA0jxbA1p3q3aZRtAUAs3puZp7rIwT4MbXmpi/uYkE1PQ3iHoDwv2gMuknN9tUcZcu Bko5nJ6dIneG1sxTux54lNt8YOTdNSq2Y+zWrvr3n4NQvH2QX4r4PesUq5IRjgwhKi8Y y5v9iZZd/OQR6XiIQMSTDR2+vmxQrRbsnI6El4Vhk+5rTKVpc65m2JDabsqgsiKNu7jt eaYg==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=VxieloCJ; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org; dara=neutral header.i=@linaro.org Return-Path: Received: from phobos.denx.de (phobos.denx.de. [2a01:238:438b:c500:173d:9f52:ddab:ee01]) by mx.google.com with ESMTPS id a640c23a62f3a-ab692cdb5edsi431965266b.566.2025.01.28.02.20.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 28 Jan 2025 02:20:42 -0800 (PST) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=VxieloCJ; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org; dara=neutral header.i=@linaro.org Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 0529481DD6; Tue, 28 Jan 2025 11:20:14 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="VxieloCJ"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id C228281D42; Tue, 28 Jan 2025 11:20:10 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-wm1-x336.google.com (mail-wm1-x336.google.com [IPv6:2a00:1450:4864:20::336]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 90274819B1 for ; Tue, 28 Jan 2025 11:20:08 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=jerome.forissier@linaro.org Received: by mail-wm1-x336.google.com with SMTP id 5b1f17b1804b1-436326dcb1cso36326345e9.0 for ; Tue, 28 Jan 2025 02:20:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1738059608; x=1738664408; darn=lists.denx.de; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=fASuFHKqVp07Z9xdr3bFH4y39Xbm1J0R9QOhNN8bHWA=; b=VxieloCJZb/C4ggcZsamG7FUXZPcTgxe332erDvCR31p4KaXk2ZpMUnn75GiOk2rGI j9XT1aBa1zMrMPN9qAosv6zX5QkN0z/xaTIlEAGFBbxbj9GipDDNLvz5peFDZJwFq53w f3OupLq05vksv2pi7vKFaHtennxOVLiw8jUoazQt+cufzcuj5SsoXsvffuhs7QBoR8Fb tiWslBiRWrFIV0VkWtj+1j/1YYl7m6UvQoOzAaeYzK+q/JHQfcV5tNeaByVJRjKA4OIV mcDNR20sF5ga9jzsPzN4RBNhPvLJGvE7niBzVIqUZP1oOGiFRfAesvB4DioTSVrflxCZ 5l2g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738059608; x=1738664408; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=fASuFHKqVp07Z9xdr3bFH4y39Xbm1J0R9QOhNN8bHWA=; b=dsFHjASSf5G+WmhyIERh5Ma/ZA6gpwaIrlTj4+dyF4onKl7Snm9L8ZTKLdNkplo3lz DsMF1nT6jfftoOvB3vm1L6mNBqZZispSCqCoAIn1rh3dFmCVvXEZSV0Olv/k5VfS+oci iGED7VgUCshGLZX19FATakGOoVXOeilBHvP4T16WB1kycwalGe78K3EZ06gbihFwSCJd hPS0mZTnVNSFo+6zOdvb0WcLI7naEdMR28PZ6GA54/szKeBWj0xOL7mLsjvwNXjzrWFg IuEUYTu2BPZGF7HvWvrWiXDQzawFwb5+G6c5ojUXraO0KIop9PKTRgcJTlNOO1d/1chL +RTg== X-Gm-Message-State: AOJu0YzFvxkqQy74CCOplLX8/VYzE9DduuWHuwmzxUM8soD260qLB7yX yI6AdOFRsAiH3lkZ7NzcljxstBG3tFElM9uT3r4qQBYdRH1F2Iy6hmZ+pZ4KJPlkem3G9sNOAdZ EZTepLg== X-Gm-Gg: ASbGncvM1P193CWo3+HY2ia5ZlB4u5vECS4gUUSpiywBwAM+E9Pz1DNgRg4Pe88sTQZ 3ikGz32Y48AHLw9OCZIGXQbdCZWWTXp+i+PTVgjURoTWglE7+/34GjGtCqOBtJTq6m/wVAQTI2+ y+mvkWaaeg+fldATHpl+HikpksIU+ZMlGDOpJ/JvE+jr2eiWszsiPJGB8b3dD7HuacmRSxLem9O MTIuJk69FWmNvrAKaK7krLeVIEtbZgt0VEqYCwtI+RLmO/ihSpteum3eO9kwSfSbvPjv4yQmIgU kghx1SzmHJn85AqWhgBYrS8= X-Received: by 2002:a05:600c:1d07:b0:436:488f:50a with SMTP id 5b1f17b1804b1-438913ef4b7mr417542515e9.17.1738059607762; Tue, 28 Jan 2025 02:20:07 -0800 (PST) Received: from builder.. ([2a01:e0a:3cb:7bb0:45e:43e2:ed61:42fe]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-438bd4b9977sm164651245e9.25.2025.01.28.02.20.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 28 Jan 2025 02:20:07 -0800 (PST) From: Jerome Forissier To: u-boot@lists.denx.de Cc: Ilias Apalodimas , Jerome Forissier , Marek Vasut , Tom Rini , Mattijs Korpershoek , Heinrich Schuchardt , Dragan Simic , Caleb Connolly Subject: [RFC PATCH v2 3/3] usb: scan multiple buses simultaneously with coroutines Date: Tue, 28 Jan 2025 11:19:17 +0100 Message-ID: <58d6721203ea81b9c20f162ef40f79bc73243a42.1738059345.git.jerome.forissier@linaro.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.8 at phobos.denx.de X-Virus-Status: Clean Use the coroutines framework to scan USB buses in parallel for better performance. Tested on arm64 QEMU on a somewhat contrived example (4 USB buses, each with one audio device, one keyboard, one mouse and one tablet). $ make qemu_arm64_defconfig $ make -j$(nproc) CROSS_COMPILE="ccache aarch64-linux-gnu-" $ qemu-system-aarch64 -M virt -nographic -cpu max -bios u-boot.bin \ $(for i in {1..4}; do echo -device qemu-xhci,id=xhci$i \ -device\ usb-{audio,kbd,mouse,tablet},bus=xhci$i.0; \ done) The time spent in usb_init() is reported on the console and shows a significant improvement with COROUTINES enabled. ** Without COROUTINES Bus xhci_pci: Register 8001040 NbrPorts 8 Starting the controller USB XHCI 1.00 Bus xhci_pci: Register 8001040 NbrPorts 8 Starting the controller USB XHCI 1.00 Bus xhci_pci: Register 8001040 NbrPorts 8 Starting the controller USB XHCI 1.00 Bus xhci_pci: Register 8001040 NbrPorts 8 Starting the controller USB XHCI 1.00 scanning bus xhci_pci for devices... 6 USB Device(s) found scanning bus xhci_pci for devices... 6 USB Device(s) found scanning bus xhci_pci for devices... 6 USB Device(s) found scanning bus xhci_pci for devices... 6 USB Device(s) found USB: 4 bus(es) scanned in 5873 ms ** With COROUTINES Bus xhci_pci: Register 8001040 NbrPorts 8 Starting the controller USB XHCI 1.00 Bus xhci_pci: Register 8001040 NbrPorts 8 Starting the controller USB XHCI 1.00 Bus xhci_pci: Register 8001040 NbrPorts 8 Starting the controller USB XHCI 1.00 Bus xhci_pci: Register 8001040 NbrPorts 8 Starting the controller USB XHCI 1.00 Scanning 4 USB bus(es)... done Bus xhci_pci: 6 USB device(s) found Bus xhci_pci: 6 USB device(s) found Bus xhci_pci: 6 USB device(s) found Bus xhci_pci: 6 USB device(s) found USB: 4 bus(es) scanned in 2213 ms Signed-off-by: Jerome Forissier --- drivers/usb/host/usb-uclass.c | 152 +++++++++++++++++++++++++++++++++- 1 file changed, 149 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index bfec303e7af..3104efe7f9e 100644 --- a/drivers/usb/host/usb-uclass.c +++ b/drivers/usb/host/usb-uclass.c @@ -9,6 +9,7 @@ #define LOG_CATEGORY UCLASS_USB #include +#include #include #include #include @@ -18,6 +19,8 @@ #include #include +#include + static bool asynch_allowed; struct usb_uclass_priv { @@ -221,6 +224,40 @@ int usb_stop(void) return err; } +static int nbus; + +#if CONFIG_IS_ENABLED(COROUTINES) +static void usb_scan_bus(struct udevice *bus, bool recurse) +{ + struct usb_bus_priv *priv; + struct udevice *dev; + int ret; + + priv = dev_get_uclass_priv(bus); + + assert(recurse); /* TODO: Support non-recusive */ + + debug("\n"); + ret = usb_scan_device(bus, 0, USB_SPEED_FULL, &dev); + if (ret) + printf("Scanning bus %s failed, error %d\n", bus->name, ret); +} + +static void usb_report_devices(struct uclass *uc) +{ + struct usb_bus_priv *priv; + struct udevice *bus; + + uclass_foreach_dev(bus, uc) { + priv = dev_get_uclass_priv(bus); + printf("Bus %s: ", bus->name); + if (priv->next_addr == 0) + printf("No USB device found\n"); + else + printf("%d USB device(s) found\n", priv->next_addr); + } +} +#else static void usb_scan_bus(struct udevice *bus, bool recurse) { struct usb_bus_priv *priv; @@ -240,7 +277,81 @@ static void usb_scan_bus(struct udevice *bus, bool recurse) printf("No USB Device found\n"); else printf("%d USB Device(s) found\n", priv->next_addr); + nbus++; } +#endif + +#if CONFIG_IS_ENABLED(COROUTINES) +extern int udelay_yield; + +static void usb_scan_bus_co(void) +{ + usb_scan_bus((struct udevice *)co_get_arg(), true); + co_exit(); +} + +static struct co_stack *stk; +static struct co *main_co; +static struct co **co; +static int co_sz = 8; + +static int add_usb_scan_bus_co(struct udevice *bus) +{ + if (!co) { + co = malloc(co_sz * sizeof(*co)); + if (!co) + return -ENOMEM; + } + if (nbus == co_sz) { + struct co **nco; + + co_sz *= 2; + nco = realloc(co, co_sz * sizeof(*co)); + if (!nco) + return -ENOMEM; + co = nco; + } + if (!main_co) { + main_co = co_create(NULL, NULL, 0, NULL, NULL); + if (!main_co) + return -ENOMEM; + } + if (!stk) { + stk = co_stack_new(32768); + if (!stk) + return -ENOMEM; + } + co[nbus] = co_create(main_co, stk, 0, usb_scan_bus_co, bus); + if (!co[nbus]) + return -ENOMEM; + nbus++; + return 0; +} + +static void usb_scan_cleanup(void) +{ + int i; + + for (i = 0; i < nbus; i++) { + co_destroy(co[i]); + co[i] = NULL; + } + nbus = 0; + co_destroy(main_co); + main_co = NULL; + co_stack_destroy(stk); + stk = NULL; +} +#else +static int add_usb_scan_bus_co(struct udevice *bus) +{ + return 0; +} + +static void usb_scan_cleanup(void) +{ +} +#endif static void remove_inactive_children(struct uclass *uc, struct udevice *bus) { @@ -289,6 +400,7 @@ static int usb_probe_companion(struct udevice *bus) int usb_init(void) { + unsigned long t0 = timer_get_us(); int controllers_initialized = 0; struct usb_uclass_priv *uc_priv; struct usb_bus_priv *priv; @@ -355,10 +467,40 @@ int usb_init(void) continue; priv = dev_get_uclass_priv(bus); - if (!priv->companion) - usb_scan_bus(bus, true); + if (!priv->companion) { + if (CONFIG_IS_ENABLED(COROUTINES)) { + ret = add_usb_scan_bus_co(bus); + if (ret) + goto out; + } else { + usb_scan_bus(bus, true); + } + } } +#if CONFIG_IS_ENABLED(COROUTINES) + { + bool done; + int i; + + printf("Scanning %d USB bus(es)... ", nbus); + udelay_yield = 0xCAFEDECA; + do { + done = true; + for (i = 0; i < nbus; i++) { + if (!co[i]->done) { + done = false; + co_resume(co[i]); + } + } + } while (!done); + udelay_yield = 0; + printf("done\n"); + + usb_report_devices(uc); + } +#endif + /* * Now that the primary controllers have been scanned and have handed * over any devices they do not understand to their companions, scan @@ -388,7 +530,11 @@ int usb_init(void) /* if we were not able to find at least one working bus, bail out */ if (controllers_initialized == 0) printf("No USB controllers found\n"); - +out: + if (nbus) + printf("USB: %d bus(es) scanned in %ld ms\n", nbus, + (timer_get_us() - t0) / 1000); + usb_scan_cleanup(); return usb_started ? 0 : -ENOENT; }