lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20251009155752.773732-109-sashal@kernel.org>
Date: Thu,  9 Oct 2025 11:56:15 -0400
From: Sasha Levin <sashal@...nel.org>
To: patches@...ts.linux.dev,
	stable@...r.kernel.org
Cc: Markus Stockhausen <markus.stockhausen@....de>,
	Daniel Lezcano <daniel.lezcano@...aro.org>,
	Stephen Howell <howels@...thatwemight.be>,
	Bjørn Mork <bjorn@...k.no>,
	Sasha Levin <sashal@...nel.org>,
	tglx@...utronix.de,
	linux-kernel@...r.kernel.org
Subject: [PATCH AUTOSEL 6.17-6.12] clocksource/drivers/timer-rtl-otto: Do not interfere with interrupts

From: Markus Stockhausen <markus.stockhausen@....de>

[ Upstream commit c445bffbf28f721e05d0ce06895045fc62aaff7c ]

During normal operation the timers are reprogrammed including an
interrupt acknowledgement. This has no effect as the whole timer
is setup from scratch afterwards. Especially in an interrupt this
has already been done by rttm_timer_interrupt().

Change the behaviour as follows:

- Use rttm_disable_timer() during reprogramming
- Keep rttm_stop_timer() for all other use cases.

Downstream has already tested and confirmed a patch. See
https://github.com/openwrt/openwrt/pull/19468
https://forum.openwrt.org/t/support-for-rtl838x-based-managed-switches/57875/3788

Signed-off-by: Markus Stockhausen <markus.stockhausen@....de>
Signed-off-by: Daniel Lezcano <daniel.lezcano@...aro.org>
Tested-by: Stephen Howell <howels@...thatwemight.be>
Tested-by: Bjørn Mork <bjorn@...k.no>
Link: https://lore.kernel.org/r/20250804080328.2609287-4-markus.stockhausen@gmx.de
Signed-off-by: Sasha Levin <sashal@...nel.org>
---

LLM Generated explanations, may be completely bogus:

YES

- What it fixes
  - The driver was acknowledging the interrupt (“W1C” PENDING bit) as
    part of routine timer reprogramming, not just in the interrupt
    handler. That read-modify-write ack can race with new pending
    interrupts and clear them, leading to occasional lost timer
    interrupts. The change confines IRQ acknowledgement to the interrupt
    handler and explicit stop/shutdown paths, preventing interference
    with in-flight or newly arriving interrupts.

- Exact code changes
  - In the reprogramming paths, `rttm_stop_timer()` (which disables the
    timer and acks the IRQ) is replaced with `rttm_disable_timer()`
    (disable only), so the PENDING bit is no longer touched during
    normal reprogramming:
    - `drivers/clocksource/timer-rtl-otto.c:141-146` changes
      reprogramming for oneshot next-event (now disable → set period →
      start, without ack).
    - `drivers/clocksource/timer-rtl-otto.c:153-159` changes
      `rttm_state_oneshot()` similarly.
    - `drivers/clocksource/timer-rtl-otto.c:166-172` changes
      `rttm_state_periodic()` similarly.
  - IRQ acknowledgement remains where it belongs:
    - Interrupt handler acks before invoking the event handler:
      `drivers/clocksource/timer-rtl-otto.c:97-106` and specifically the
      ack helper at `drivers/clocksource/timer-rtl-otto.c:77-80`.
    - Stop/shutdown/init paths still ack via `rttm_stop_timer()`:
      - Shutdown: `drivers/clocksource/timer-rtl-otto.c:175-182`
      - Setup: `drivers/clocksource/timer-rtl-otto.c:185-190`
      - `rttm_stop_timer()` itself still does disable + ack:
        `drivers/clocksource/timer-rtl-otto.c:125-129`.

- Why the original behavior is problematic
  - The ack function is implemented as a read-modify-write to a W1C bit:
    `ioread32(base + RTTM_INT) | RTTM_INT_PENDING` followed by a write
    (`drivers/clocksource/timer-rtl-otto.c:77-80`). If a new interrupt
    becomes pending between the read and the write, the write will still
    set the PENDING bit in the value and clear it on write, effectively
    dropping that freshly latched interrupt. Calling this sequence
    outside the ISR (e.g., during reprogramming) can therefore interfere
    with normal interrupt delivery.

- Why this change is safe
  - In-ISR reprogramming: The handler already acknowledges the interrupt
    at entry (`drivers/clocksource/timer-rtl-otto.c:102`). Removing a
    second ack during reprogramming eliminates a window where a new
    pending interrupt could be inadvertently cleared.
  - Non-ISR reprogramming: If a pending bit exists, not acking ensures
    it will be properly handled by the ISR when it fires, rather than
    being silently cleared by a stray reprogramming ack.
  - Ack is still performed at shutdown/setup where it is appropriate to
    clear stale state (`drivers/clocksource/timer-rtl-otto.c:175-190`),
    so there is no accumulation of stale flags.

- Context and related fixes
  - This change is part of a small, focused series addressing timer
    reliability on Realtek Otto platforms:
    - “Work around dying timers” added `rttm_bounce_timer()` to avoid
      reprogramming in a critical ~5us window before expiry (hardware
      peculiarity) and is used directly before reprogramming in all the
      altered paths (`drivers/clocksource/timer-rtl-otto.c:109-123` and
      calls at 141, 154, 167).
    - “Drop set_counter” cleaned up a no-op write to the current
      counter.
  - The series was tested downstream (OpenWrt) and carries multiple
    Tested-by tags; the commit under review also notes downstream
    confirmation.

- Backport considerations
  - Scope: Single driver file; changes are three substitutions of
    `rttm_stop_timer()` with `rttm_disable_timer()` in reprogramming
    paths. No functional/ABI changes outside this driver.
  - Dependencies: None strict. If a stable branch does not yet have
    `rttm_bounce_timer()`, the underlying correctness argument for using
    `rttm_disable_timer()` instead of `rttm_stop_timer()` during
    reprogramming still holds. For branches already including the bounce
    patch (as in newer stables), this applies cleanly.
  - Risk: Low. Potential for an extra immediate interrupt if a PENDING
    bit remained set is mitigated because the ISR acks and the
    clockevents layer tolerates such re-entries; conversely, the change
    removes a race that could drop interrupts, which is more severe.

- Stable policy fit
  - Fixes a real bug affecting users (lost or interfered interrupts on
    rtl-otto platforms).
  - Small, contained, and without architectural changes.
  - Confined to `drivers/clocksource/timer-rtl-otto.c`.
  - Already tested downstream and reviewed/merged upstream (commit
    c445bffbf28f7).
  - While there is no explicit “Cc: stable” in the commit message, the
    change meets stable backport criteria and aligns with the prior
    reliability fix series for this driver.

Conclusion: Backporting this patch reduces the risk of lost timer
interrupts by avoiding unnecessary and racy IRQ acknowledgements during
reprogramming, with minimal regression risk and limited scope.

 drivers/clocksource/timer-rtl-otto.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/clocksource/timer-rtl-otto.c b/drivers/clocksource/timer-rtl-otto.c
index 8be45a11fb8b6..24c4aa6a30131 100644
--- a/drivers/clocksource/timer-rtl-otto.c
+++ b/drivers/clocksource/timer-rtl-otto.c
@@ -147,7 +147,7 @@ static int rttm_next_event(unsigned long delta, struct clock_event_device *clkev
 
 	RTTM_DEBUG(to->of_base.base);
 	rttm_bounce_timer(to->of_base.base, RTTM_CTRL_COUNTER);
-	rttm_stop_timer(to->of_base.base);
+	rttm_disable_timer(to->of_base.base);
 	rttm_set_period(to->of_base.base, delta);
 	rttm_start_timer(to, RTTM_CTRL_COUNTER);
 
@@ -160,7 +160,7 @@ static int rttm_state_oneshot(struct clock_event_device *clkevt)
 
 	RTTM_DEBUG(to->of_base.base);
 	rttm_bounce_timer(to->of_base.base, RTTM_CTRL_COUNTER);
-	rttm_stop_timer(to->of_base.base);
+	rttm_disable_timer(to->of_base.base);
 	rttm_set_period(to->of_base.base, RTTM_TICKS_PER_SEC / HZ);
 	rttm_start_timer(to, RTTM_CTRL_COUNTER);
 
@@ -173,7 +173,7 @@ static int rttm_state_periodic(struct clock_event_device *clkevt)
 
 	RTTM_DEBUG(to->of_base.base);
 	rttm_bounce_timer(to->of_base.base, RTTM_CTRL_TIMER);
-	rttm_stop_timer(to->of_base.base);
+	rttm_disable_timer(to->of_base.base);
 	rttm_set_period(to->of_base.base, RTTM_TICKS_PER_SEC / HZ);
 	rttm_start_timer(to, RTTM_CTRL_TIMER);
 
-- 
2.51.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ