Re: The state of Xenomai 4 on Xilinx Zynq-7000 (or ARM32 in general)

Gerte Hoogewerf <[email protected]>
Newsgroups dev.linux.lists.xenomai
Message-ID <CAKndYJGm0Ne6_fMkrNmQoE92LZmSghyH23CYmht0Ogs-obRH1A@mail.gmail.com>
Hi Jan/Philippe,

Philippe wrote:
> [..] the following patch allows the socfpga to boot, could you please try it on the Zynq?

Thanks for the patch. That patch doesn't make it better or worse; it's
an orthogonal problem and my configuration wasn't affected by it.

Jan wrote:
> That would indeed be welcome already.

We will try to participate.

> [..] I had to manually enable CONFIG_VDSO

Noted. Thanks for the tip.

With a bit of AI research, I landed on something that fixes the
problem for me on "smp_twd" with CONFIG_SMP=y. I'll share the attached
patch to provide further insight into the problem. It may not be the
best candidate for direct adoption, but hopefully it'll shed some
light on the problem.

Furthermore, here's the AI's explanation:

> On Zynq-7000, smp_twd.c sets CLOCK_EVT_FEAT_C3STOP on the TWD unless the DT node
> has "always-on". With no broadcast device registered, tick_is_oneshot_available() never
> returns true, so Linux never switches that CPU to oneshot; and tick_install_proxy() just
> reads td->mode rather than forcing the switch, so the EVL proxy inherits periodic mode too
> and the in-band relay never gets armed. Jiffies freeze silently until the first real timed sleep
> hangs forever.

For me, the "timed sleep" involved a network driver toggling the PHY
reset.  It was asking the kernel for a one second delay (via
"jiffies"), while jiffies was basically stuck. This is why our
original boot attempts never reached userland.

An earlier, simplified, workaround didn't change any C code, but
merely the DTB (oneliner below). I considered it "a shameless hack",
but wanted to share it anyway:

> scutimer: timer@f8f00600 {
>      ...
>      compatible = "arm,cortex-a9-twd-timer";
>      ...
> ++   always-on;  //  workaround!!!
> };

I hope that's helpful. I'm more than happy to try alternative fixes or
future versions. At our organization, we will probably need to upgrade
away from ipipe and getting Dovetail to work properly on Zynq-7000
would be the logical next step for us.

Best,

Gerte Hoogewerf
Senior Software Team Lead
LMI Technologies
Wiebachstraat 25b, Kerkrade 6466 NG, The Netherlands

-- 


This
email and any attachment(s) it may contain is confidential and is 
intended
solely for the use of the individual(s) to whom it is addressed. 
If you are not
the intended recipient of this email, you must not take 
action based on the
contents, nor distribute, nor expose any part of the 
content(s) to entities or
person(s) beyond the original distribution list. 
Please contact the sender and
delete the email if you have received it in 
error. Thank you.
0001-evl-force-oneshot-takeover-of-proxy-tick-device-on-i.patch (text/plain, 4.2 KB)
From 36310dbba405d3e99e8e9a6756a71ef14c89e833 Mon Sep 17 00:00:00 2001
From: Gerte Hoogewerf <[email protected]>
Date: Tue, 18 Aug 2026 06:34:11 +0200
Subject: [PATCH] evl: force oneshot takeover of proxy tick device on install

---
 kernel/time/tick-proxy.c | 80 +++++++++++++++++++++++++---------------
 1 file changed, 50 insertions(+), 30 deletions(-)

diff --git a/kernel/time/tick-proxy.c b/kernel/time/tick-proxy.c
index 5a877987a84e..38af6cafc818 100644
--- a/kernel/time/tick-proxy.c
+++ b/kernel/time/tick-proxy.c
@@ -267,16 +267,63 @@ int tick_setup_proxy(struct clock_proxy_device *dev)
 	return 0;
 }
 
-static int enable_oob_timer(void *arg) /* hard_irqs_disabled() */
+struct proxy_install_arg {
+	void (*setup_proxy)(struct clock_proxy_device *dev);
+	int result;
+};
+
+static int install_proxy_and_takeover(void *arg) /* hard_irqs_disabled(), all CPUs stopped */
 {
+	struct proxy_install_arg *req = arg;
 	struct clock_proxy_device *dev = raw_cpu_ptr(&proxy_tick_device);
+	struct tick_device *td = tick_get_device(smp_processor_id());
 	struct clock_event_device *real_dev;
+	int ret;
+
+	/*
+	 * tick_setup_device() picks periodic vs. oneshot setup for
+	 * the incoming proxy device from td->mode alone, without
+	 * re-checking whether the real device could actually complete
+	 * that switch on its own (e.g. a C3STOP clockevent with no
+	 * broadcast device wired up never leaves periodic mode on
+	 * stock Linux). We take over dispatch for this device
+	 * unconditionally past this point, so any such Linux-side
+	 * precondition no longer applies: force the switch here.
+	 */
+	if (td->mode != TICKDEV_MODE_ONESHOT) {
+		td->mode = TICKDEV_MODE_ONESHOT;
+		/*
+		 * The real device's next_event was never driven by
+		 * genuine oneshot reprogramming while in periodic
+		 * mode, so it holds a stale or uninitialized deadline.
+		 * tick_setup_device() is about to inherit it verbatim
+		 * as the proxy's first oneshot deadline; seed it with
+		 * a sane one now so that inheritance doesn't hand the
+		 * reprogram loop in tick_handle_periodic() a deadline
+		 * far enough away to overflow ktime_t negative once a
+		 * tick period gets added to it.
+		 */
+		if (td->evtdev)
+			td->evtdev->next_event = ktime_get();
+	}
+
+	dev->__setup_handler = req->setup_proxy;
+	ret = clockevents_register_proxy(dev);
+	if (ret) {
+		if (!req->result)
+			req->result = ret;
+		return 0;
+	}
+	dev->real_device->event_handler = proxy_event_handler;
 
 	/*
 	 * Install the out-of-band handler on this CPU's real clock
 	 * device, then turn on out-of-band mode for the associated
 	 * IRQ (duplicates are silently ignored if the IRQ is common
-	 * to multiple CPUs).
+	 * to multiple CPUs). Carrying this out in the same stopped-
+	 * machine context as the registration above closes the
+	 * window where a genuine tick could otherwise land on the
+	 * real device between the two steps, mid-handover.
 	 */
 	real_dev = dev->real_device;
 	real_dev->event_handler = dev->handle_oob_event;
@@ -293,27 +340,6 @@ static int enable_oob_timer(void *arg) /* hard_irqs_disabled() */
 	return 0;
 }
 
-struct proxy_install_arg {
-	void (*setup_proxy)(struct clock_proxy_device *dev);
-	int result;
-};
-
-static void register_proxy_device(void *arg) /* irqs_disabled() */
-{
-	struct clock_proxy_device *dev = raw_cpu_ptr(&proxy_tick_device);
-	struct proxy_install_arg *req = arg;
-	int ret;
-
-	dev->__setup_handler = req->setup_proxy;
-	ret = clockevents_register_proxy(dev);
-	if (ret) {
-		if (!req->result)
-			req->result = ret;
-	} else {
-		dev->real_device->event_handler = proxy_event_handler;
-	}
-}
-
 int tick_install_proxy(void (*setup_proxy)(struct clock_proxy_device *dev),
 		const struct cpumask *cpumask)
 {
@@ -392,17 +418,11 @@ int tick_install_proxy(void (*setup_proxy)(struct clock_proxy_device *dev),
 	 */
 	arg.setup_proxy = setup_proxy;
 	arg.result = 0;
-	on_each_cpu_mask(cpumask, register_proxy_device, &arg, true);
+	stop_machine(install_proxy_and_takeover, &arg, cpumask);
 	if (arg.result) {
 		tick_uninstall_proxy(cpumask);
 		return arg.result;
 	}
-
-	/*
-	 * Start ticking from the out-of-band interrupt stage upon
-	 * receipt of out-of-band timer events.
-	 */
-	stop_machine(enable_oob_timer, NULL, cpumask);
 out:
 	mutex_unlock(&proxy_mutex);
 
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.