| Message ID | 20260725113341.2250687-1-megi@xff.cz (mailing list archive) |
|---|---|
| State | New |
| Headers |
Return-Path: <linux-sunxi+bounces-24765-sunxi=pue.re@lists.linux.dev> X-Original-To: noreply@patchwork.local Delivered-To: noreply@patchwork.local Received: from sea.lore.kernel.org (sea.lore.kernel.org [172.234.253.10]) by mxe881.netcup.net (Postfix) with ESMTPS id 721B51C2A82 for <noreply@patchwork.local>; Sat, 25 Jul 2026 13:34:43 +0200 (CEST) Authentication-Results: mxe881; dkim=pass header.d=xff.cz; spf=pass (sender IP is 172.234.253.10) smtp.mailfrom=linux-sunxi+bounces-24765-noreply=patchwork.local@lists.linux.dev smtp.helo=sea.lore.kernel.org Received-SPF: pass (mxe881: domain of lists.linux.dev designates 172.234.253.10 as permitted sender) client-ip=172.234.253.10; envelope-from=linux-sunxi+bounces-24765-noreply=patchwork.local@lists.linux.dev; helo=sea.lore.kernel.org; Received: from smtp.subspace.kernel.org (conduit.subspace.kernel.org [100.90.174.1]) by sea.lore.kernel.org (Postfix) with ESMTP id 9014E302BBBC for <noreply@patchwork.local>; Sat, 25 Jul 2026 11:33:51 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 3013D3BED31; Sat, 25 Jul 2026 11:33:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=xff.cz header.i=@xff.cz header.b="U2Y1AvV7" X-Original-To: linux-sunxi@lists.linux.dev Received: from vps.xff.cz (vps.xff.cz [195.181.215.36]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E89BA3AA195 for <linux-sunxi@lists.linux.dev>; Sat, 25 Jul 2026 11:33:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=195.181.215.36 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784979231; cv=none; b=JxXB9E8gh3Gjw13T9imBN0v1e0RK2I6NLWNoA2l/LDb2nCVHJ8eLHz//hMQ1rnPmy8MVOmxqsMfm6FENPZvXCv9NqVdguh0gNAqTcPy+YvnMcnBv8mIg4HSI0y2Wd7A6nl0c9nvLdYj3/7zsCrerrcHkb9X8L5FByRZkZQakIdQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784979231; c=relaxed/simple; bh=+cmBvCWySQzLhKfWmPtp9rjSjfEJGBKKXbEo16iheG8=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=fgK6R2TPbW+3NYjzHNAawhqgu+0JNs4aC6eZTJb3CVws5H8kp7Ilil1AQw7jMt5EG8fBFB89yijvXSvwXZ/K4fpz9rfxzoC7T3j+rV+9I/EUlK8HcEktBtcyER5W4f7rk1znbu7t3ap3tL7HTYJ11hoc9QzZklhtHcNxuqd4Ym4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=xff.cz; spf=pass smtp.mailfrom=xff.cz; dkim=pass (1024-bit key) header.d=xff.cz header.i=@xff.cz header.b=U2Y1AvV7; arc=none smtp.client-ip=195.181.215.36 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=xff.cz Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=xff.cz DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=xff.cz; s=mail; t=1784979227; bh=+cmBvCWySQzLhKfWmPtp9rjSjfEJGBKKXbEo16iheG8=; h=From:To:Cc:Subject:Date:From; b=U2Y1AvV7YbCbbUt+dVubN2FyLQA95eRZFQ2bdWiY0KNB5ATJVio+r/M5w75IWAmSJ ISnLZ/6ld0vqzaKoEuGX5j8Qn+oFToq4mqsBKXrZzt8M3rM5i83C8NbWslZ/aZ0Elv ziO13yN44xDomfyUuLiPFzAb0iFNmjT2VgnoEuZ8= From: =?utf-8?q?Ond=C5=99ej_Jirman?= <megi@xff.cz> To: linux-sunxi@lists.linux.dev Cc: linux-kernel@vger.kernel.org, Ondrej Jirman <megi@xff.cz>, Daniel Lezcano <daniel.lezcano@kernel.org>, Thomas Gleixner <tglx@kernel.org>, Chen-Yu Tsai <wens@kernel.org>, Jernej Skrabec <jernej.skrabec@gmail.com>, Samuel Holland <samuel@sholland.org>, Maxime Ripard <mripard@kernel.org>, linux-arm-kernel@lists.infradead.org (moderated list:ARM/Allwinner sunXi SoC support) Subject: [PATCH] clocksource/drivers/sun4i: Wait for pending reload before CTRL write Date: Sat, 25 Jul 2026 13:33:38 +0200 Message-ID: <20260725113341.2250687-1-megi@xff.cz> Precedence: bulk X-Mailing-List: linux-sunxi@lists.linux.dev List-Id: <linux-sunxi.lists.linux.dev> List-Subscribe: <mailto:linux-sunxi+subscribe@lists.linux.dev> List-Unsubscribe: <mailto:linux-sunxi+unsubscribe@lists.linux.dev> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Rspamd-Server: rspamd-worker-8404 X-Spamd-Result: default: False [-0.66 / 15.00]; BAYES_HAM(-5.50)[100.00%]; RBL_SENDERSCORE(2.00)[172.234.253.10:from]; SUSPICIOUS_RECIPS(1.50)[]; MID_CONTAINS_FROM(1.00)[]; R_MISSING_CHARSET(0.50)[]; MAILLIST(-0.15)[generic]; MIME_GOOD(-0.10)[text/plain]; BAD_REP_POLICIES(0.10)[]; HAS_LIST_UNSUB(-0.01)[]; FROM_HAS_DN(0.00)[]; PRECEDENCE_BULK(0.00)[]; TAGGED_RCPT(0.00)[]; FUZZY_BLOCKED(0.00)[rspamd.com]; FREEMAIL_CC(0.00)[vger.kernel.org,xff.cz,kernel.org,gmail.com,sholland.org,lists.infradead.org]; DBL_BLOCKED_OPENRESOLVER(0.00)[sea.lore.kernel.org:rdns,sea.lore.kernel.org:helo,xff.cz:email,xff.cz:dkim]; R_DKIM_ALLOW(0.00)[xff.cz:s=mail]; FROM_NEQ_ENVFROM(0.00)[megi@xff.cz,linux-sunxi@lists.linux.dev]; ARC_ALLOW(0.00)[subspace.kernel.org:s=arc-20240116:i=1]; DKIM_TRACE(0.00)[xff.cz:+]; DMARC_POLICY_ALLOW(0.00)[xff.cz,none]; RCVD_COUNT_THREE(0.00)[4]; R_SPF_ALLOW(0.00)[+ip4:172.234.253.10]; FORGED_SENDER_MAILLIST(0.00)[]; RCPT_COUNT_SEVEN(0.00)[10]; MIME_TRACE(0.00)[0:+]; TAGGED_FROM(0.00)[bounces-24765-noreply=patchwork.local]; FORGED_RECIPIENTS_MAILLIST(0.00)[]; ASN(0.00)[asn:63949, ipnet:172.234.224.0/19, country:SG]; RCVD_TLS_LAST(0.00)[]; TO_DN_SOME(0.00)[] X-Rspamd-Queue-Id: 721B51C2A82 X-MORS-Enabled: yes X-MORS-DOMAIN: patchwork.local X-MORS-HOSTING: hosting172546 X-MORS-USER: hosting172546 X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= |
| Series |
clocksource/drivers/sun4i: Wait for pending reload before CTRL write
|
|
Commit Message
Ondřej Jirman
July 25, 2026, 11:33 a.m. UTC
From: Ondrej Jirman <megi@xff.cz> The A13 manual says of TMR0_RELOAD: "After the bit is set, it can not be written again before it's cleared automatically." Both time_stop() and time_start() read-modify-write the control register, so a reload still in flight gets rewritten and the write can be dropped, leaving the timer unarmed. In oneshot mode this happens on every tick, and the tick eventually stops for good. Wait for the reload to clear first. All control register updates go through sun4i_clkevt_time_stop(). Without this my Allwinner A13 based Pocketbook Touch Lux 3 stops scheduling processes during boot or within a few seconds of executing userspace. Only sysrq+t over serial port works at this stage, which is how I discovered the root cause. Fixes: 7e14183469d8 ("clocksource: sun4i: Fix bug when switching from periodic to oneshot modes") Signed-off-by: Ondrej Jirman <megi@xff.cz> --- BTW, similar issue will likely be also in timer-sun5i.c but I don't have any device that would exercise it. And it's possible that this triggers more easily with CONFIG_HZ=1000 which I use. drivers/clocksource/timer-sun4i.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-)
Comments
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: Pre-existing issues: - [High] This problem wasn't introduced by this patch, but the same hardware limitation where writing to the control register while the RELOAD bit is set causes the write to be dropped is unaddressed in `timer-sun5i.c`. -- --- Patch [1]: [PATCH] clocksource/drivers/sun4i: Wait for pending reload before CTRL write --- commit 936f66d7fd8614d6358ab1a1c7241c4675c9fff4 Author: Ondrej Jirman <megi@xff.cz> clocksource/drivers/sun4i: Wait for pending reload before CTRL write This commit fixes a bug in the sun4i timer driver where writes to the control register are silently dropped if the RELOAD bit is set. It introduces a polling mechanism to wait for the reload bit to clear before modifying the register. > BTW, similar issue will likely be also in timer-sun5i.c but I don't have any > device that would exercise it. And it's possible that this triggers more easily > with CONFIG_HZ=1000 which I use. [Severity: High] This isn't a bug introduced by this patch, but as you suspected, the exact same hardware limitation is unaddressed in drivers/clocksource/timer-sun5i.c. Looking at sun5i_clkevt_time_stop(), the unprotected read-modify-write of the control register occurs here: drivers/clocksource/timer-sun5i.c:sun5i_clkevt_time_stop() { ... writel(val & ~TIMER_CTL_ENABLE, ce->base + TIMER_CTL_REG(timer, offset)); ... } If rapid back-to-back scheduling of high-resolution timers causes this to be called while the RELOAD bit from a prior time_start() is still set, wouldn't the write be dropped, failing to clear the ENABLE bit? Since this can permanently stop clock events and cause the system to freeze by halting process scheduling, should a similar wait mechanism be applied to the sun5i timer to protect devices that use it as a clockevent device?
Well, that's what I stated in the original patch comment. I don't have the HW to test. I can send a blind fix, or whoever cares and has SoC that uses the other timer driver that may have the same issue, can do it. I'll do whatever the real maintainers suggest. ;) .o On Sat, Jul 25, 2026 at 11:43:38AM +0000, sashiko-bot@kernel.org wrote: > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: > > Pre-existing issues: > - [High] This problem wasn't introduced by this patch, but the same hardware limitation where writing to the control register while the RELOAD bit is set causes the write to be dropped is unaddressed in `timer-sun5i.c`. > -- > > --- Patch [1]: [PATCH] clocksource/drivers/sun4i: Wait for pending reload before CTRL write --- > commit 936f66d7fd8614d6358ab1a1c7241c4675c9fff4 > Author: Ondrej Jirman <megi@xff.cz> > > clocksource/drivers/sun4i: Wait for pending reload before CTRL write > > This commit fixes a bug in the sun4i timer driver where writes to the > control register are silently dropped if the RELOAD bit is set. It introduces > a polling mechanism to wait for the reload bit to clear before modifying > the register. > > > BTW, similar issue will likely be also in timer-sun5i.c but I don't have any > > device that would exercise it. And it's possible that this triggers more easily > > with CONFIG_HZ=1000 which I use. > > [Severity: High] > This isn't a bug introduced by this patch, but as you suspected, the exact > same hardware limitation is unaddressed in drivers/clocksource/timer-sun5i.c. > > Looking at sun5i_clkevt_time_stop(), the unprotected read-modify-write of > the control register occurs here: > > drivers/clocksource/timer-sun5i.c:sun5i_clkevt_time_stop() { > ... > writel(val & ~TIMER_CTL_ENABLE, > ce->base + TIMER_CTL_REG(timer, offset)); > ... > } > > If rapid back-to-back scheduling of high-resolution timers causes this to > be called while the RELOAD bit from a prior time_start() is still set, > wouldn't the write be dropped, failing to clear the ENABLE bit? > > Since this can permanently stop clock events and cause the system to freeze > by halting process scheduling, should a similar wait mechanism be applied > to the sun5i timer to protect devices that use it as a clockevent device? > > -- > Sashiko AI review · https://sashiko.dev/#/patchset/20260725113341.2250687-1-megi@xff.cz?part=1
diff --git a/drivers/clocksource/timer-sun4i.c b/drivers/clocksource/timer-sun4i.c index 7bdcc60ad43c..2e7457f671c4 100644 --- a/drivers/clocksource/timer-sun4i.c +++ b/drivers/clocksource/timer-sun4i.c @@ -39,6 +39,9 @@ #define TIMER_SYNC_TICKS 3 +/* The reload bit clears a couple of source clock cycles after it is set. */ +#define TIMER_RELOAD_MAX_POLL 100 + /* * When we disable a timer, we need to wait at least for 2 cycles of * the timer source clock. We will use for that the clocksource timer @@ -53,9 +56,30 @@ static void sun4i_clkevt_sync(void __iomem *base) cpu_relax(); } +/* + * The control register must not be written while a reload is still in + * flight, or the write can be dropped. + */ +static int sun4i_clkevt_wait_reload(void __iomem *base, u8 timer) +{ + int i; + + for (i = 0; i < TIMER_RELOAD_MAX_POLL; i++) { + if (!(readl(base + TIMER_CTL_REG(timer)) & TIMER_CTL_RELOAD)) + return 0; + cpu_relax(); + } + + return -ETIME; +} + static void sun4i_clkevt_time_stop(void __iomem *base, u8 timer) { - u32 val = readl(base + TIMER_CTL_REG(timer)); + u32 val; + + sun4i_clkevt_wait_reload(base, timer); + + val = readl(base + TIMER_CTL_REG(timer)); writel(val & ~TIMER_CTL_ENABLE, base + TIMER_CTL_REG(timer)); sun4i_clkevt_sync(base); }