linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] clocksource/drivers/arm_arch_timer: Fix XGene-1 TVAL register math error
@ 2022-11-21 14:53 Marc Zyngier
  2022-11-22  8:11 ` Daniel Lezcano
  0 siblings, 1 reply; 2+ messages in thread
From: Marc Zyngier @ 2022-11-21 14:53 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel
  Cc: Thomas Gleixner, daniel.lezcano, Joe Korty, stable

From: Joe Korty <joe.korty@concurrent-rt.com>

The TVAL register is 32 bit signed.  Thus only the lower 31 bits are
available to specify when an interrupt is to occur at some time in the
near future.  Attempting to specify a larger interval with TVAL results
in a negative time delta which means the timer fires immediately upon
being programmed, rather than firing at that expected future time.

The solution is for Linux to declare that TVAL is a 31 bit register rather
than give its true size of 32 bits.  This prevents Linux from programming
TVAL with a too-large value.  Note that, prior to 5.16, this little trick
was the standard way to handle TVAL in Linux, so there is nothing new
happening here on that front.

The softlockup detector hides the issue, because it keeps generating
short timer deadlines that are within the scope of the broken timer.

Disable it, and you start using NO_HZ with much longer timer deadlines,
which turns into an interrupt flood:

 11: 1124855130  949168462  758009394   76417474  104782230   30210281
         310890 1734323687     GICv2  29 Level     arch_timer

And "much longer" isn't that long: it takes less than 43s to underflow
TVAL at 50MHz (the frequency of the counter on XGene-1).

Some comments on the v1 version of this patch by Marc Zyngier:

  XGene implements CVAL (a 64bit comparator) in terms of TVAL (a countdown
  register) instead of the other way around. TVAL being a 32bit register,
  the width of the counter should equally be 32.  However, TVAL is a
  *signed* value, and keeps counting down in the negative range once the
  timer fires.

  It means that any TVAL value with bit 31 set will fire immediately,
  as it cannot be distinguished from an already expired timer. Reducing
  the timer range back to a paltry 31 bits papers over the issue.

  Another problem cannot be fixed though, which is that the timer interrupt
  *must* be handled within the negative countdown period, or the interrupt
  will be lost (TVAL will rollover to a positive value, indicative of a
  new timer deadline).

Cc: stable@vger.kernel.org # 5.16+
Fixes: 012f18850452 ("clocksource/drivers/arm_arch_timer: Work around broken CVAL implementations")
Signed-off-by: Joe Korty <joe.korty@concurrent-rt.com>
Reviewed-by: Marc Zyngier <maz@kernel.org>
[maz: revamped the commit message]
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20221024165422.GA51107@zipoli.concurrent-rt.com
---

Notes:
    v3: rejigged commit message along the lines of the v2 review.

 drivers/clocksource/arm_arch_timer.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index a7ff77550e17..41323c2bc0b1 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -806,6 +806,9 @@ static u64 __arch_timer_check_delta(void)
 		/*
 		 * XGene-1 implements CVAL in terms of TVAL, meaning
 		 * that the maximum timer range is 32bit. Shame on them.
+		 *
+		 * Note that TVAL is signed, thus has only 31 of its
+		 * 32 bits to express magnitude.
 		 */
 		MIDR_ALL_VERSIONS(MIDR_CPU_MODEL(ARM_CPU_IMP_APM,
 						 APM_CPU_PART_POTENZA)),
@@ -813,8 +816,8 @@ static u64 __arch_timer_check_delta(void)
 	};
 
 	if (is_midr_in_range_list(read_cpuid_id(), broken_cval_midrs)) {
-		pr_warn_once("Broken CNTx_CVAL_EL1, limiting width to 32bits");
-		return CLOCKSOURCE_MASK(32);
+		pr_warn_once("Broken CNTx_CVAL_EL1, using 32 bit TVAL instead.\n");
+		return CLOCKSOURCE_MASK(31);
 	}
 #endif
 	return CLOCKSOURCE_MASK(arch_counter_get_width());
-- 
2.34.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] clocksource/drivers/arm_arch_timer: Fix XGene-1 TVAL register math error
  2022-11-21 14:53 [PATCH] clocksource/drivers/arm_arch_timer: Fix XGene-1 TVAL register math error Marc Zyngier
@ 2022-11-22  8:11 ` Daniel Lezcano
  0 siblings, 0 replies; 2+ messages in thread
From: Daniel Lezcano @ 2022-11-22  8:11 UTC (permalink / raw)
  To: Marc Zyngier, linux-arm-kernel, linux-kernel
  Cc: Thomas Gleixner, Joe Korty, stable

On 21/11/2022 15:53, Marc Zyngier wrote:
> From: Joe Korty <joe.korty@concurrent-rt.com>
> 
> The TVAL register is 32 bit signed.  Thus only the lower 31 bits are
> available to specify when an interrupt is to occur at some time in the
> near future.  Attempting to specify a larger interval with TVAL results
> in a negative time delta which means the timer fires immediately upon
> being programmed, rather than firing at that expected future time.
> 
> The solution is for Linux to declare that TVAL is a 31 bit register rather
> than give its true size of 32 bits.  This prevents Linux from programming
> TVAL with a too-large value.  Note that, prior to 5.16, this little trick
> was the standard way to handle TVAL in Linux, so there is nothing new
> happening here on that front.
> 
> The softlockup detector hides the issue, because it keeps generating
> short timer deadlines that are within the scope of the broken timer.
> 
> Disable it, and you start using NO_HZ with much longer timer deadlines,
> which turns into an interrupt flood:
> 
>   11: 1124855130  949168462  758009394   76417474  104782230   30210281
>           310890 1734323687     GICv2  29 Level     arch_timer
> 
> And "much longer" isn't that long: it takes less than 43s to underflow
> TVAL at 50MHz (the frequency of the counter on XGene-1).
> 
> Some comments on the v1 version of this patch by Marc Zyngier:
> 
>    XGene implements CVAL (a 64bit comparator) in terms of TVAL (a countdown
>    register) instead of the other way around. TVAL being a 32bit register,
>    the width of the counter should equally be 32.  However, TVAL is a
>    *signed* value, and keeps counting down in the negative range once the
>    timer fires.
> 
>    It means that any TVAL value with bit 31 set will fire immediately,
>    as it cannot be distinguished from an already expired timer. Reducing
>    the timer range back to a paltry 31 bits papers over the issue.
> 
>    Another problem cannot be fixed though, which is that the timer interrupt
>    *must* be handled within the negative countdown period, or the interrupt
>    will be lost (TVAL will rollover to a positive value, indicative of a
>    new timer deadline).
> 
> Cc: stable@vger.kernel.org # 5.16+
> Fixes: 012f18850452 ("clocksource/drivers/arm_arch_timer: Work around broken CVAL implementations")
> Signed-off-by: Joe Korty <joe.korty@concurrent-rt.com>
> Reviewed-by: Marc Zyngier <maz@kernel.org>
> [maz: revamped the commit message]
> Signed-off-by: Marc Zyngier <maz@kernel.org>
> Link: https://lore.kernel.org/r/20221024165422.GA51107@zipoli.concurrent-rt.com
> ---

Applied


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2022-11-22  8:12 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-11-21 14:53 [PATCH] clocksource/drivers/arm_arch_timer: Fix XGene-1 TVAL register math error Marc Zyngier
2022-11-22  8:11 ` Daniel Lezcano

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).