[PATCH 0/3] Fix NXP STM clockevent bugs causing lockups
flat view
DORMANTno replies
From: Enric Balletbo i Serra via B4 Relay <devnull+eballetb.redhat.com@kernel.org>
Date: 2026-10-26 08:44:55
Also in:
b4-sent, linux-rt-devel, lkml, stable
Subsystem:
clocksource, clockevent drivers, the rest · Maintainers:
Daniel Lezcano, Thomas Gleixner, Linus Torvalds
This series fixes three bugs in the NXP STM clocksource driver that can
cause soft lockups and missed timer events, particularly visible on
PREEMPT_RT kernels running on S32G platforms.
The NXP STM generates an interrupt only on exact match between the
counter and comparator registers. If the counter passes the programmed
value, the match is missed and the hardware must count through all 2^32
ticks (~32.2s at 133 MHz) before firing, causing soft lockups.
Patch 1 fixes max_delta: on 64-bit platforms, ULONG_MAX exceeds the
hardware's 32-bit compare register width, making it possible to program
an unreachable compare value.
Patch 2 fixes the overshoot detection in set_next_event: the existing
check only detected counter wraps, not the normal case where the counter
advances past the programmed value during the read-modify-write window.
Replace it with a signed comparison following the pattern used by
timer-imx-gpt.
Patch 3 increases min_delta from 2us to 20us: under bus contention on
PREEMPT_RT, 2us is not enough margin and the counter frequently
overshoots the programmed value, triggering repeated -ETIME retries.
The lockup can be reproduced on an unpatched S32G board with:
# ./trigger_lockup &
# stress-ng --matrix 0 --memthrash 0 & dmesg -w | grep -i "soft lockup"
Where trigger_lockup.c is:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <sched.h>
#include <unistd.h>
void *timer_hammer(void *arg) {
long cpu = (long)arg;
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(cpu, &cpuset);
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
/* Request 1 ns to force the kernel to clamp to min_delta (2 us) */
struct timespec req = { .tv_sec = 0, .tv_nsec = 1 };
while (1) {
clock_nanosleep(CLOCK_MONOTONIC, 0, &req, NULL);
}
return NULL;
}
int main(void) {
long ncpus = sysconf(_SC_NPROCESSORS_ONLN);
pthread_t threads[ncpus];
printf("[+] Hammering hrtimers with minimal deltas across %ld cores...\n", ncpus);
printf("[+] Check dmesg for: 'BUG: soft lockup - CPU#... stuck for 32s!'\n");
for (long i = 0; i < ncpus; i++) {
pthread_create(&threads[i], NULL, timer_hammer, (void *)i);
}
for (long i = 0; i < ncpus; i++) {
pthread_join(threads[i], NULL);
}
return 0;
}
The soft lockup trace looks like:
watchdog: BUG: soft lockup - CPU#1 stuck for 32s! [swapper/1:0]
Modules linked in: nft_ct nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib
nft_masq nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4
nf_tables veth bridge stp llc rfkill binfmt_misc nls_ascii nls_cp437 vfat
fat ina2xx rtc_pcf85063 regmap_spi micrel phy_package aquantia crc_itu_t
ci_hdrc_imx dwmac_s32 crct10dif_ce ci_hdrc ghash_ce stmmac_platform
sha2_ce sha256_arm64 sha1_ce udc_core stmmac ulpi phy_generic pcs_xpcs
usbmisc_imx phylink ptp pps_core i2c_imx fsl_edma virt_dma flexcan
can_dev s32g_wdt watchdog sch_fq_codel drm fuse drm_panel_orientation_quirks
nfnetlink dmi_sysfs ipv6
CPU: 1 UID: 0 PID: 0 Comm: swapper/1 Tainted: G X ------ --- 6.12.0-274.el10iv.aarch64 #1 PREEMPT_RT
Tainted: [X]=AUX
Hardware name: Unknown Unknown Product/Unknown Product, BIOS 2022.04-15.el10_4 04/01/2022
pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
pc : default_idle_call+0x3c/0x170
lr : default_idle_call+0x30/0x170
sp : ffff80008011bdd0
x29: ffff80008011bdd0 x28: 0000000000000000 x27: 0000000000000000
x26: 0000000000000000 x25: 0000000000000000 x24: 0000000000000000
x23: 00000000000000c0 x22: ffff0008803ac840 x21: ffff0008803ac840
x20: 0000000000000000 x19: 0000000000000000 x18: 0000000000000000
x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000
x14: 003369266b813144 x13: 0000000000000000 x12: 00000000000002eb
x11: 00000000000000c0 x10: 00000000000010a0 x9 : ffff800080350ff4
x8 : ffff0008803ad940 x7 : 0000000000000000 x6 : 0000000000000000
x5 : 0000000000000004 x4 : 0000000000c1c684 x3 : 0000000000000001
x2 : ffff0008803ac840 x1 : ffff800081712628 x0 : 0000000000000001
Call trace:
default_idle_call+0x3c/0x170 (P)
cpuidle_idle_call+0x1a8/0x248
do_idle+0xa4/0x118
cpu_startup_entry+0x3c/0x50
secondary_start_kernel+0x124/0x168
__secondary_switched+0xc0/0xc8
hrtimer: interrupt took 7246 ns
Signed-off-by: Enric Balletbo i Serra <redacted>
---
Enric Balletbo i Serra (3):
clocksource/drivers/nxp-stm: Fix max_delta overflow on 64-bit platforms
clocksource/drivers/nxp-stm: Fix missed comparator match in set_next_event
clocksource/drivers/nxp-stm: Increase min_delta to 20us for PREEMPT_RT
drivers/clocksource/timer-nxp-stm.c | 26 +++++++++++---------------
1 file changed, 11 insertions(+), 15 deletions(-)
---
base-commit: 734bef548a96e8774d6eef5dfa2026c6edc4e80b
change-id: 20261023-nxp-stm-fixes-ab0163517e6f
Best regards,
--
Enric Balletbo i Serra [off-list ref]