diff mbox series

[v3,08/14] lib: time: hook uthread_schedule() into udelay()

Message ID 20250304152510.2832340-9-jerome.forissier@linaro.org
State New
Headers show
Series Uthreads | expand

Commit Message

Jerome Forissier March 4, 2025, 3:24 p.m. UTC
Introduce a uthread scheduling loop into udelay() when CONFIG_UTHREAD
is enabled. This means that any uthread calling into udelay() may yield
to uthread and be scheduled again later. The granunlarity of the
scheduling loop is defined by CONFIG_UTHREAD_GRANULARITY. The lower the
value, the tighter the loop. The default value of 10 ms was chosen by
testing the concurrent initialization of the two USB busses of an
i.MX93 board (introduced in a later commit). The total time is as
follows:

  UTHREAD_GRANULARITY (us) |  "usb start" time (s)
  -------------------------+----------------------
                         0 |                2.426
                      1000 |                2.448
                     10000 |                2.512
                    100000 |                2.992
                    300000 |                3.407

For reference, if uthread_schedule() is not called at all in udelay()
except once via schedule(), the "usb start" time is 4.377s and without
UTHREAD it is 4.591 s.

Signed-off-by: Jerome Forissier <jerome.forissier@linaro.org>
---
 lib/Kconfig |  8 ++++++++
 lib/time.c  | 21 ++++++++++++++++++++-
 2 files changed, 28 insertions(+), 1 deletion(-)

Comments

Jerome Forissier March 5, 2025, 5:32 p.m. UTC | #1
On 3/4/25 16:24, Jerome Forissier wrote:
> Introduce a uthread scheduling loop into udelay() when CONFIG_UTHREAD
> is enabled. This means that any uthread calling into udelay() may yield
> to uthread and be scheduled again later. The granunlarity of the
> scheduling loop is defined by CONFIG_UTHREAD_GRANULARITY. The lower the
> value, the tighter the loop. The default value of 10 ms was chosen by
> testing the concurrent initialization of the two USB busses of an
> i.MX93 board (introduced in a later commit). The total time is as
> follows:
> 
>   UTHREAD_GRANULARITY (us) |  "usb start" time (s)
>   -------------------------+----------------------
>                          0 |                2.426
>                       1000 |                2.448
>                      10000 |                2.512
>                     100000 |                2.992
>                     300000 |                3.407
> 
> For reference, if uthread_schedule() is not called at all in udelay()
> except once via schedule(), the "usb start" time is 4.377s and without
> UTHREAD it is 4.591 s.

Replying to myself... but I have done some more tests on the i.MX93 and
this UTHREAD_GRANULARITY delay is not good. The console drops characters
as soon as it is greater than 5 microseconds. That's after running
"spawn sleep 10" -- the console becomes buggy during 10 seconds then back
to normal. With UTHREAD_GRANULARITY=0 all is fine.

Therefore I consider dropping UTHREAD_GRANULARITY in v4 and using a tight
loop like in v2 [1].

[1] https://lists.denx.de/pipermail/u-boot/2025-February/581634.html
diff mbox series

Patch

diff --git a/lib/Kconfig b/lib/Kconfig
index 8321f20e154..40964f5bb4a 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -1276,6 +1276,14 @@  config UTHREAD_STACK_SIZE
 	  When the stack_sz argument to uthread_create() is zero then this
 	  value is used.
 
+config UTHREAD_GRANULARITY
+	int "Scheduling period for uthreads inside udelay()"
+	depends on UTHREAD
+	default 10000
+	help
+	  The delay in microseconds between calls to uthread_schedule() inside
+	  the udelay() function.
+
 endmenu
 
 source "lib/fwu_updates/Kconfig"
diff --git a/lib/time.c b/lib/time.c
index d88edafb196..7c34424bf64 100644
--- a/lib/time.c
+++ b/lib/time.c
@@ -17,6 +17,7 @@ 
 #include <asm/global_data.h>
 #include <asm/io.h>
 #include <linux/delay.h>
+#include <uthread.h>
 
 #ifndef CFG_WD_PERIOD
 # define CFG_WD_PERIOD	(10 * 1000 * 1000)	/* 10 seconds default */
@@ -190,6 +191,23 @@  void __weak __udelay(unsigned long usec)
 
 /* ------------------------------------------------------------------------- */
 
+static void do_delay(unsigned long kv)
+{
+#if CONFIG_IS_ENABLED(UTHREAD)
+	ulong t0 = timer_get_us();
+	ulong gr = CONFIG_UTHREAD_GRANULARITY;
+
+	if (kv < CONFIG_UTHREAD_GRANULARITY)
+		gr = kv;
+	while (timer_get_us() - t0 < kv) {
+		uthread_schedule();
+		__udelay(gr);
+	}
+#else
+	__udelay(kv);
+#endif
+}
+
 void udelay(unsigned long usec)
 {
 	ulong kv;
@@ -197,7 +215,8 @@  void udelay(unsigned long usec)
 	do {
 		schedule();
 		kv = usec > CFG_WD_PERIOD ? CFG_WD_PERIOD : usec;
-		__udelay(kv);
+		do_delay(kv);
 		usec -= kv;
 	} while(usec);
+
 }