* [PATCH] ARM: fix get_cycles() always returning zero
@ 2026-08-27 9:54 Tapio Reijonen
0 siblings, 0 replies; only message in thread
From: Tapio Reijonen @ 2026-08-27 9:54 UTC (permalink / raw)
To: Russell King, Thomas Gleixner
Cc: linux-arm-kernel, linux-kernel, Tapio Reijonen
Commit dfc256dac54c ("calibrate: Rework delay timer calibration")
renamed read_current_timer() to delay_read_timer() and inverted its
return convention: the old function returned 0 on success, the new one
returns true on success. The ternary in get_cycles() was not updated,
so it now evaluates to 0 whenever the delay timer is present and
readable, which is precisely when it used to work.
__timer_delay() then never terminates:
cycles_t start = get_cycles(); /* 0 */
while ((get_cycles() - start) < cycles) /* 0 - 0 < cycles */
cpu_relax();
so any udelay() asking for a non-zero number of cycles hangs the CPU
forever. On an i.MX6SX this stops the boot in the first udelay(10) of
i2c_gpio_init_recovery(), reached from i2c_imx_probe():
calling i2c_adap_imx_init+0x0/0x18 @ 1
watchdog: BUG: soft lockup - CPU#0 stuck for 22s! [swapper/0:1]
PC is at __timer_delay+0x44/0x58
__timer_delay from i2c_register_adapter+0x604/0x7ec
i2c_register_adapter from i2c_imx_probe+0x3f0/0x6a4
Calls with a zero cycle count still returned, which is why the failure
only appears once a driver requests a real delay.
Arm is the only architecture still defining get_cycles() in terms of
this helper; the other users of the old interface had their get_cycles()
removed by the same commit, so they are unaffected.
Swap the ternary arms so that a successful read yields the counter
value again. random_get_entropy() is built on get_cycles() and was
silently falling back for the same reason.
Fixes: dfc256dac54c ("calibrate: Rework delay timer calibration")
Signed-off-by: Tapio Reijonen <tapio.reijonen@vaisala.com>
---
I ran into this on an i.MX6SX, where the boot stops in the first udelay(10) of
i2c_gpio_init_recovery() and the soft lockup detector reports the CPU stuck in
__timer_delay(). Instrumenting __timer_const_udelay() showed that the requested
cycle count was correct, which is what pointed at get_cycles() rather than at
the delay parameters. I have verified on that board that the change below makes
it boot again.
Arm appears to be the only architecture still deriving get_cycles() from this
helper, since the same commit removed get_cycles() from the other timex.h files
it touched, so I do not think anything else is affected. I have not been able to
test any other platform.
This leaves any arm32 platform with a registered delay timer unbootable, so it
would be good to get it in before v7.3-rc1.
---
arch/arm/include/asm/timex.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/include/asm/timex.h b/arch/arm/include/asm/timex.h
index 94e40c19cfc5747866aeb78075c80ec90f1d1d15..4d31eab9dba2111a858e1010594d6f340159b948 100644
--- a/arch/arm/include/asm/timex.h
+++ b/arch/arm/include/asm/timex.h
@@ -13,7 +13,7 @@ typedef unsigned long cycles_t;
// Temporary workaround until timex.h is cleaned up
bool delay_read_timer(unsigned long *t);
-#define get_cycles() ({ cycles_t c; delay_read_timer(&c) ? 0 : c; })
+#define get_cycles() ({ cycles_t c; delay_read_timer(&c) ? c : 0; })
#define random_get_entropy() (((unsigned long)get_cycles()) ?: random_get_entropy_fallback())
#endif
---
base-commit: 91ec2035134982b98fab0609a9fd8480e8217dc1
change-id: 20260827-arm-get-cycles-4aadad692050
Best regards,
--
Tapio Reijonen <tapio.reijonen@vaisala.com>
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-08-27 9:55 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-27 9:54 [PATCH] ARM: fix get_cycles() always returning zero Tapio Reijonen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox