linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] clocksource/arm_arch_timer: Fix masking for high freq counters
@ 2021-08-07 19:14 Oliver Upton
  2021-08-07 22:30 ` Linus Walleij
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Oliver Upton @ 2021-08-07 19:14 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-kernel, Mark Rutland, Marc Zyngier, Daniel Lezcano,
	Thomas Gleixner, Peter Shier, Raghavendra Rao Ananta,
	Ricardo Koller, Oliver Upton

Unfortunately, the architecture provides no means to determine the bit
width of the system counter. However, we do know the following from the
specification:

 - the system counter is at least 56 bits wide
 - Roll-over time of not less than 40 years

To date, the arch timer driver has depended on the first property,
assuming any system counter to be 56 bits wide and masking off the rest.
However, combining a narrow clocksource mask with a high frequency
counter could result in prematurely wrapping the system counter by a
significant margin. For example, a 56 bit wide, 1GHz system counter
would wrap in a mere 2.28 years!

This is a problem for two reasons: v8.6+ implementations are required to
provide a 64 bit, 1GHz system counter. Furthermore, before v8.6,
implementers may select a counter frequency of their choosing.

Fix the issue by deriving a valid clock mask based on the second
property from above. Set the floor at 56 bits, since we know no system
counter is narrower than that.

Suggested-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Oliver Upton <oupton@google.com>
---
This patch was tested on QEMU, tweaked to provide a 1GHz system counter
frequency. The 'bp.refcounter.base_frequency' property does not seem to
have any affect on the 'ARMvA Base RevC AEM FVP', and instead provides a
100MHz counter.

Parent commit: 0c32706dac1b ("arm64: stacktrace: avoid tracing arch_stack_walk()")

 drivers/clocksource/arm_arch_timer.c | 32 ++++++++++++++++++++++++----
 1 file changed, 28 insertions(+), 4 deletions(-)

diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index be6d741d404c..f4816b22213c 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -52,6 +52,12 @@
 #define CNTV_TVAL	0x38
 #define CNTV_CTL	0x3c
 
+/*
+ * The minimum amount of time a generic counter is guaranteed to not roll over
+ * (40 years)
+ */
+#define MIN_ROLLOVER_SECS	(40ULL * 365 * 24 * 3600)
+
 static unsigned arch_timers_present __initdata;
 
 static void __iomem *arch_counter_base __ro_after_init;
@@ -205,13 +211,11 @@ static struct clocksource clocksource_counter = {
 	.id	= CSID_ARM_ARCH_COUNTER,
 	.rating	= 400,
 	.read	= arch_counter_read,
-	.mask	= CLOCKSOURCE_MASK(56),
 	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
 static struct cyclecounter cyclecounter __ro_after_init = {
 	.read	= arch_counter_read_cc,
-	.mask	= CLOCKSOURCE_MASK(56),
 };
 
 struct ate_acpi_oem_info {
@@ -1004,9 +1008,26 @@ struct arch_timer_kvm_info *arch_timer_get_kvm_info(void)
 	return &arch_timer_kvm_info;
 }
 
+/*
+ * Makes an educated guess at a valid counter width based on the Generic Timer
+ * specification. Of note:
+ *   1) the system counter is at least 56 bits wide
+ *   2) a roll-over time of not less than 40 years
+ *
+ * See 'ARM DDI 0487G.a D11.1.2 ("The system counter")' for more details.
+ */
+static int __init arch_counter_get_width(void)
+{
+	u64 min_cycles = MIN_ROLLOVER_SECS * arch_timer_rate;
+
+	/* guarantee the returned width is within the valid range */
+	return clamp_val(ilog2(min_cycles), 56, 64);
+}
+
 static void __init arch_counter_register(unsigned type)
 {
 	u64 start_count;
+	int width;
 
 	/* Register the CP15 based counter if we have one */
 	if (type & ARCH_TIMER_TYPE_CP15) {
@@ -1031,6 +1052,10 @@ static void __init arch_counter_register(unsigned type)
 		arch_timer_read_counter = arch_counter_get_cntvct_mem;
 	}
 
+	width = arch_counter_get_width();
+	clocksource_counter.mask = CLOCKSOURCE_MASK(width);
+	cyclecounter.mask = CLOCKSOURCE_MASK(width);
+
 	if (!arch_counter_suspend_stop)
 		clocksource_counter.flags |= CLOCK_SOURCE_SUSPEND_NONSTOP;
 	start_count = arch_timer_read_counter();
@@ -1040,8 +1065,7 @@ static void __init arch_counter_register(unsigned type)
 	timecounter_init(&arch_timer_kvm_info.timecounter,
 			 &cyclecounter, start_count);
 
-	/* 56 bits minimum, so we assume worst case rollover */
-	sched_clock_register(arch_timer_read_counter, 56, arch_timer_rate);
+	sched_clock_register(arch_timer_read_counter, width, arch_timer_rate);
 }
 
 static void arch_timer_stop(struct clock_event_device *clk)
-- 
2.32.0.605.g8dce9f2422-goog


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

* Re: [PATCH v2] clocksource/arm_arch_timer: Fix masking for high freq counters
  2021-08-07 19:14 [PATCH v2] clocksource/arm_arch_timer: Fix masking for high freq counters Oliver Upton
@ 2021-08-07 22:30 ` Linus Walleij
  2021-08-08  1:14   ` Oliver Upton
  2021-08-08 10:29   ` Marc Zyngier
  2021-08-09 11:07 ` Marc Zyngier
  2021-10-24 15:39 ` [tip: timers/core] clocksource/drivers/arm_arch_timer: " tip-bot2 for Oliver Upton
  2 siblings, 2 replies; 10+ messages in thread
From: Linus Walleij @ 2021-08-07 22:30 UTC (permalink / raw)
  To: Oliver Upton
  Cc: Linux ARM, linux-kernel, Mark Rutland, Marc Zyngier,
	Daniel Lezcano, Thomas Gleixner, Peter Shier,
	Raghavendra Rao Ananta, Ricardo Koller

On Sat, Aug 7, 2021 at 9:14 PM Oliver Upton <oupton@google.com> wrote:

> Unfortunately, the architecture provides no means to determine the bit
> width of the system counter. However, we do know the following from the
> specification:
>
>  - the system counter is at least 56 bits wide
>  - Roll-over time of not less than 40 years
>
> To date, the arch timer driver has depended on the first property,
> assuming any system counter to be 56 bits wide and masking off the rest.
> However, combining a narrow clocksource mask with a high frequency
> counter could result in prematurely wrapping the system counter by a
> significant margin. For example, a 56 bit wide, 1GHz system counter
> would wrap in a mere 2.28 years!
>
> This is a problem for two reasons: v8.6+ implementations are required to
> provide a 64 bit, 1GHz system counter. Furthermore, before v8.6,
> implementers may select a counter frequency of their choosing.
>
> Fix the issue by deriving a valid clock mask based on the second
> property from above. Set the floor at 56 bits, since we know no system
> counter is narrower than that.
>
> Suggested-by: Marc Zyngier <maz@kernel.org>
> Signed-off-by: Oliver Upton <oupton@google.com>

This patch looks good to me:
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Just a thought that crossed my mind: as this is real hardware we are
talking about mostly, how hard would it be for arch_counter_get_width()
to detect how wide it actually is if nbits > 56?

I would do something like this pseudocode:

nbits = 56;
while (nbits < 64)
    startval = GENMASK(nbits, 0);
    write_counter(startval);
    start_counter;
    nsleep(1);
    stop_counter;
    now = read_counter;
    if (now < startval)
         /* Ooops it wrapped */
         break;
    nbits++

pr_info("counter has %d bits\n", nbits);

Or did you folks already try this approach?

Yours,
Linus Walleij

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

* Re: [PATCH v2] clocksource/arm_arch_timer: Fix masking for high freq counters
  2021-08-07 22:30 ` Linus Walleij
@ 2021-08-08  1:14   ` Oliver Upton
  2021-08-08 10:40     ` Marc Zyngier
  2021-08-08 10:29   ` Marc Zyngier
  1 sibling, 1 reply; 10+ messages in thread
From: Oliver Upton @ 2021-08-08  1:14 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Linux ARM, linux-kernel, Mark Rutland, Marc Zyngier,
	Daniel Lezcano, Thomas Gleixner, Peter Shier,
	Raghavendra Rao Ananta, Ricardo Koller

Hi Linus,

On Sat, Aug 7, 2021 at 3:30 PM Linus Walleij <linus.walleij@linaro.org> wrote:
>
> On Sat, Aug 7, 2021 at 9:14 PM Oliver Upton <oupton@google.com> wrote:
>
> > Unfortunately, the architecture provides no means to determine the bit
> > width of the system counter. However, we do know the following from the
> > specification:
> >
> >  - the system counter is at least 56 bits wide
> >  - Roll-over time of not less than 40 years
> >
> > To date, the arch timer driver has depended on the first property,
> > assuming any system counter to be 56 bits wide and masking off the rest.
> > However, combining a narrow clocksource mask with a high frequency
> > counter could result in prematurely wrapping the system counter by a
> > significant margin. For example, a 56 bit wide, 1GHz system counter
> > would wrap in a mere 2.28 years!
> >
> > This is a problem for two reasons: v8.6+ implementations are required to
> > provide a 64 bit, 1GHz system counter. Furthermore, before v8.6,
> > implementers may select a counter frequency of their choosing.
> >
> > Fix the issue by deriving a valid clock mask based on the second
> > property from above. Set the floor at 56 bits, since we know no system
> > counter is narrower than that.
> >
> > Suggested-by: Marc Zyngier <maz@kernel.org>
> > Signed-off-by: Oliver Upton <oupton@google.com>
>
> This patch looks good to me:
> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
>

Thanks for the review!

> Just a thought that crossed my mind: as this is real hardware we are
> talking about mostly, how hard would it be for arch_counter_get_width()
> to detect how wide it actually is if nbits > 56?
>
> I would do something like this pseudocode:
>
> nbits = 56;
> while (nbits < 64)
>     startval = GENMASK(nbits, 0);
>     write_counter(startval);
>     start_counter;
>     nsleep(1);
>     stop_counter;
>     now = read_counter;
>     if (now < startval)
>          /* Ooops it wrapped */
>          break;
>     nbits++
>
> pr_info("counter has %d bits\n", nbits);
>
> Or did you folks already try this approach?

This would be a good idea, although I believe our only means of
offsetting the counter are available in EL2. I had thought we could
use a CVAL register instead, but this quote from the ARM ARM doesn't
imply the CVAL bit width matches that of the system counter:

<quote>
If the Generic counter is implemented at a size less than 64 bits,
then this field is permitted to be implemented at the same width as
the counter, and the upper bits are RES0.
</quote>

The only other sane idea that I could come up with is providing this
information to the kernel through DT, although that would leave ACPI
systems behind.

--
Thanks,
Oliver

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

* Re: [PATCH v2] clocksource/arm_arch_timer: Fix masking for high freq counters
  2021-08-07 22:30 ` Linus Walleij
  2021-08-08  1:14   ` Oliver Upton
@ 2021-08-08 10:29   ` Marc Zyngier
  1 sibling, 0 replies; 10+ messages in thread
From: Marc Zyngier @ 2021-08-08 10:29 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Oliver Upton, Linux ARM, linux-kernel, Mark Rutland,
	Daniel Lezcano, Thomas Gleixner, Peter Shier,
	Raghavendra Rao Ananta, Ricardo Koller

On Sat, 07 Aug 2021 23:30:20 +0100,
Linus Walleij <linus.walleij@linaro.org> wrote:
> 
> On Sat, Aug 7, 2021 at 9:14 PM Oliver Upton <oupton@google.com> wrote:
> 
> > Unfortunately, the architecture provides no means to determine the bit
> > width of the system counter. However, we do know the following from the
> > specification:
> >
> >  - the system counter is at least 56 bits wide
> >  - Roll-over time of not less than 40 years
> >
> > To date, the arch timer driver has depended on the first property,
> > assuming any system counter to be 56 bits wide and masking off the rest.
> > However, combining a narrow clocksource mask with a high frequency
> > counter could result in prematurely wrapping the system counter by a
> > significant margin. For example, a 56 bit wide, 1GHz system counter
> > would wrap in a mere 2.28 years!
> >
> > This is a problem for two reasons: v8.6+ implementations are required to
> > provide a 64 bit, 1GHz system counter. Furthermore, before v8.6,
> > implementers may select a counter frequency of their choosing.
> >
> > Fix the issue by deriving a valid clock mask based on the second
> > property from above. Set the floor at 56 bits, since we know no system
> > counter is narrower than that.
> >
> > Suggested-by: Marc Zyngier <maz@kernel.org>
> > Signed-off-by: Oliver Upton <oupton@google.com>
> 
> This patch looks good to me:
> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
> 
> Just a thought that crossed my mind: as this is real hardware we are
> talking about mostly, how hard would it be for arch_counter_get_width()
> to detect how wide it actually is if nbits > 56?
> 
> I would do something like this pseudocode:
> 
> nbits = 56;
> while (nbits < 64)
>     startval = GENMASK(nbits, 0);
>     write_counter(startval);

That's where things stop. The counter is not writable, and for good
reasons (it is shared with all the CPUs in the system).

>     start_counter;
>     nsleep(1);
>     stop_counter;
>     now = read_counter;
>     if (now < startval)
>          /* Ooops it wrapped */
>          break;
>     nbits++
> 
> pr_info("counter has %d bits\n", nbits);
> 
> Or did you folks already try this approach?

The only way to emulate this behaviour is to use CNTVOFF_EL2 at EL2 to
offset a guest view of the counter, and to run minimal guest that will
do the start/stop/compare work. Given that it involves running a guest
at a point where we are unable to do so, and that it cannot work when
booted at EL1, we're left with guesswork.

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

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

* Re: [PATCH v2] clocksource/arm_arch_timer: Fix masking for high freq counters
  2021-08-08  1:14   ` Oliver Upton
@ 2021-08-08 10:40     ` Marc Zyngier
  2021-08-08 19:01       ` Oliver Upton
  0 siblings, 1 reply; 10+ messages in thread
From: Marc Zyngier @ 2021-08-08 10:40 UTC (permalink / raw)
  To: Oliver Upton
  Cc: Linus Walleij, Linux ARM, linux-kernel, Mark Rutland,
	Daniel Lezcano, Thomas Gleixner, Peter Shier,
	Raghavendra Rao Ananta, Ricardo Koller

On Sun, 08 Aug 2021 02:14:35 +0100,
Oliver Upton <oupton@google.com> wrote:

> The only other sane idea that I could come up with is providing this
> information to the kernel through DT, although that would leave ACPI
> systems behind.

It also has the disadvantage that a large number of DT timer nodes are
a mess of cargo-culted, copy-pasted idioms, and that adding another
property would only make it worse. I'm more confident with something
that can be either:

- checked from EL2 using CNTVOFF, which is complicated, doesn't work
  at EL1, and leaves us in a weird state if we have different counter
  width views in the system (BL is such a wonderful concept)

- or computed from first principle based on the requirements of the
  architecture.

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

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

* Re: [PATCH v2] clocksource/arm_arch_timer: Fix masking for high freq counters
  2021-08-08 10:40     ` Marc Zyngier
@ 2021-08-08 19:01       ` Oliver Upton
  2021-08-09 10:45         ` Marc Zyngier
  0 siblings, 1 reply; 10+ messages in thread
From: Oliver Upton @ 2021-08-08 19:01 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Linus Walleij, Linux ARM, linux-kernel, Mark Rutland,
	Daniel Lezcano, Thomas Gleixner, Peter Shier,
	Raghavendra Rao Ananta, Ricardo Koller

On Sun, Aug 8, 2021 at 3:40 AM Marc Zyngier <maz@kernel.org> wrote:
>
> On Sun, 08 Aug 2021 02:14:35 +0100,
> Oliver Upton <oupton@google.com> wrote:
>
> > The only other sane idea that I could come up with is providing this
> > information to the kernel through DT, although that would leave ACPI
> > systems behind.
>
> It also has the disadvantage that a large number of DT timer nodes are
> a mess of cargo-culted, copy-pasted idioms, and that adding another
> property would only make it worse.

Agreed, this does seem like the best solution, short of the
architecture actually providing something to determine the counter
width.

On that note, I wonder how (if ever) we will be able to move away from
unnecessarily masking a 64 bit counter, i.e. a v8.6 or above
implementation. With this patch, one such counter would wrap after
36.56 years, short of the 40 year guarantee we have from the
architecture for < v8.6 implementations. Getting it to 64 bits would
squarely make it someone else's problem ~585 years from now :)

--
Thanks,
Oliver

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

* Re: [PATCH v2] clocksource/arm_arch_timer: Fix masking for high freq counters
  2021-08-08 19:01       ` Oliver Upton
@ 2021-08-09 10:45         ` Marc Zyngier
  2021-08-09 15:08           ` Oliver Upton
  0 siblings, 1 reply; 10+ messages in thread
From: Marc Zyngier @ 2021-08-09 10:45 UTC (permalink / raw)
  To: Oliver Upton
  Cc: Linus Walleij, Linux ARM, linux-kernel, Mark Rutland,
	Daniel Lezcano, Thomas Gleixner, Peter Shier,
	Raghavendra Rao Ananta, Ricardo Koller

On Sun, 08 Aug 2021 20:01:10 +0100,
Oliver Upton <oupton@google.com> wrote:
> 
> On Sun, Aug 8, 2021 at 3:40 AM Marc Zyngier <maz@kernel.org> wrote:
> >
> > On Sun, 08 Aug 2021 02:14:35 +0100,
> > Oliver Upton <oupton@google.com> wrote:
> >
> > > The only other sane idea that I could come up with is providing this
> > > information to the kernel through DT, although that would leave ACPI
> > > systems behind.
> >
> > It also has the disadvantage that a large number of DT timer nodes are
> > a mess of cargo-culted, copy-pasted idioms, and that adding another
> > property would only make it worse.
> 
> Agreed, this does seem like the best solution, short of the
> architecture actually providing something to determine the counter
> width.
> 
> On that note, I wonder how (if ever) we will be able to move away from
> unnecessarily masking a 64 bit counter, i.e. a v8.6 or above
> implementation. With this patch, one such counter would wrap after
> 36.56 years, short of the 40 year guarantee we have from the
> architecture for < v8.6 implementations. Getting it to 64 bits would
> squarely make it someone else's problem ~585 years from now :)

Hmmm. If you end-up with something that falls short of 40 years, then
I suspect something is wrong in the way you compute the required
width.

40 years @1GHz (which we shall call FY1G from now on) fits comfortably
in 61 bits, and I fear that your use of ilog2() gives you one less bit
than what it should be:

log2(FY1G) ~= 60.13

What you are after is probably (ilog2(FY1G - 1) + 1), similar to the
way roundup_pow_of_two() works.

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

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

* Re: [PATCH v2] clocksource/arm_arch_timer: Fix masking for high freq counters
  2021-08-07 19:14 [PATCH v2] clocksource/arm_arch_timer: Fix masking for high freq counters Oliver Upton
  2021-08-07 22:30 ` Linus Walleij
@ 2021-08-09 11:07 ` Marc Zyngier
  2021-10-24 15:39 ` [tip: timers/core] clocksource/drivers/arm_arch_timer: " tip-bot2 for Oliver Upton
  2 siblings, 0 replies; 10+ messages in thread
From: Marc Zyngier @ 2021-08-09 11:07 UTC (permalink / raw)
  To: Oliver Upton
  Cc: linux-arm-kernel, linux-kernel, Mark Rutland, Daniel Lezcano,
	Thomas Gleixner, Peter Shier, Raghavendra Rao Ananta,
	Ricardo Koller

On Sat, 07 Aug 2021 20:14:28 +0100,
Oliver Upton <oupton@google.com> wrote:
> 
> Unfortunately, the architecture provides no means to determine the bit
> width of the system counter. However, we do know the following from the
> specification:
> 
>  - the system counter is at least 56 bits wide
>  - Roll-over time of not less than 40 years
> 
> To date, the arch timer driver has depended on the first property,
> assuming any system counter to be 56 bits wide and masking off the rest.
> However, combining a narrow clocksource mask with a high frequency
> counter could result in prematurely wrapping the system counter by a
> significant margin. For example, a 56 bit wide, 1GHz system counter
> would wrap in a mere 2.28 years!
> 
> This is a problem for two reasons: v8.6+ implementations are required to
> provide a 64 bit, 1GHz system counter. Furthermore, before v8.6,
> implementers may select a counter frequency of their choosing.
> 
> Fix the issue by deriving a valid clock mask based on the second
> property from above. Set the floor at 56 bits, since we know no system
> counter is narrower than that.
> 
> Suggested-by: Marc Zyngier <maz@kernel.org>
> Signed-off-by: Oliver Upton <oupton@google.com>
> ---
> This patch was tested on QEMU, tweaked to provide a 1GHz system counter
> frequency. The 'bp.refcounter.base_frequency' property does not seem to
> have any affect on the 'ARMvA Base RevC AEM FVP', and instead provides a
> 100MHz counter.
> 
> Parent commit: 0c32706dac1b ("arm64: stacktrace: avoid tracing arch_stack_walk()")
> 
>  drivers/clocksource/arm_arch_timer.c | 32 ++++++++++++++++++++++++----
>  1 file changed, 28 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
> index be6d741d404c..f4816b22213c 100644
> --- a/drivers/clocksource/arm_arch_timer.c
> +++ b/drivers/clocksource/arm_arch_timer.c
> @@ -52,6 +52,12 @@
>  #define CNTV_TVAL	0x38
>  #define CNTV_CTL	0x3c
>  
> +/*
> + * The minimum amount of time a generic counter is guaranteed to not roll over
> + * (40 years)
> + */
> +#define MIN_ROLLOVER_SECS	(40ULL * 365 * 24 * 3600)
> +
>  static unsigned arch_timers_present __initdata;
>  
>  static void __iomem *arch_counter_base __ro_after_init;
> @@ -205,13 +211,11 @@ static struct clocksource clocksource_counter = {
>  	.id	= CSID_ARM_ARCH_COUNTER,
>  	.rating	= 400,
>  	.read	= arch_counter_read,
> -	.mask	= CLOCKSOURCE_MASK(56),
>  	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
>  };
>  
>  static struct cyclecounter cyclecounter __ro_after_init = {
>  	.read	= arch_counter_read_cc,
> -	.mask	= CLOCKSOURCE_MASK(56),
>  };
>  
>  struct ate_acpi_oem_info {
> @@ -1004,9 +1008,26 @@ struct arch_timer_kvm_info *arch_timer_get_kvm_info(void)
>  	return &arch_timer_kvm_info;
>  }
>  
> +/*
> + * Makes an educated guess at a valid counter width based on the Generic Timer
> + * specification. Of note:
> + *   1) the system counter is at least 56 bits wide
> + *   2) a roll-over time of not less than 40 years
> + *
> + * See 'ARM DDI 0487G.a D11.1.2 ("The system counter")' for more details.
> + */
> +static int __init arch_counter_get_width(void)
> +{
> +	u64 min_cycles = MIN_ROLLOVER_SECS * arch_timer_rate;
> +
> +	/* guarantee the returned width is within the valid range */
> +	return clamp_val(ilog2(min_cycles), 56, 64);

See my comment somewhere else in the thread about the potential wasted
bit.

> +}
> +
>  static void __init arch_counter_register(unsigned type)
>  {
>  	u64 start_count;
> +	int width;
>  
>  	/* Register the CP15 based counter if we have one */
>  	if (type & ARCH_TIMER_TYPE_CP15) {
> @@ -1031,6 +1052,10 @@ static void __init arch_counter_register(unsigned type)
>  		arch_timer_read_counter = arch_counter_get_cntvct_mem;
>  	}
>  
> +	width = arch_counter_get_width();
> +	clocksource_counter.mask = CLOCKSOURCE_MASK(width);
> +	cyclecounter.mask = CLOCKSOURCE_MASK(width);
> +
>  	if (!arch_counter_suspend_stop)
>  		clocksource_counter.flags |= CLOCK_SOURCE_SUSPEND_NONSTOP;
>  	start_count = arch_timer_read_counter();
> @@ -1040,8 +1065,7 @@ static void __init arch_counter_register(unsigned type)
>  	timecounter_init(&arch_timer_kvm_info.timecounter,
>  			 &cyclecounter, start_count);
>  
> -	/* 56 bits minimum, so we assume worst case rollover */
> -	sched_clock_register(arch_timer_read_counter, 56, arch_timer_rate);
> +	sched_clock_register(arch_timer_read_counter, width, arch_timer_rate);

For the record, there is one spot where the clockevent gets registered
and configured that also needs addressing (there is a mask harcoded to
31 bits there, which is pretty odd). It cannot be fixed directly in
this patch though. I'll probably take this patch on top of my series
and adjust the relevant bits.

	M.

-- 
Without deviation from the norm, progress is not possible.

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

* Re: [PATCH v2] clocksource/arm_arch_timer: Fix masking for high freq counters
  2021-08-09 10:45         ` Marc Zyngier
@ 2021-08-09 15:08           ` Oliver Upton
  0 siblings, 0 replies; 10+ messages in thread
From: Oliver Upton @ 2021-08-09 15:08 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Linus Walleij, Linux ARM, linux-kernel, Mark Rutland,
	Daniel Lezcano, Thomas Gleixner, Peter Shier,
	Raghavendra Rao Ananta, Ricardo Koller

On Mon, Aug 9, 2021 at 3:45 AM Marc Zyngier <maz@kernel.org> wrote:
> > On that note, I wonder how (if ever) we will be able to move away from
> > unnecessarily masking a 64 bit counter, i.e. a v8.6 or above
> > implementation. With this patch, one such counter would wrap after
> > 36.56 years, short of the 40 year guarantee we have from the
> > architecture for < v8.6 implementations. Getting it to 64 bits would
> > squarely make it someone else's problem ~585 years from now :)
>
> Hmmm. If you end-up with something that falls short of 40 years, then
> I suspect something is wrong in the way you compute the required
> width.
>
> 40 years @1GHz (which we shall call FY1G from now on) fits comfortably
> in 61 bits, and I fear that your use of ilog2() gives you one less bit
> than what it should be:
>
> log2(FY1G) ~= 60.13

Right, this is round-down behavior was deliberate. Reading the ARM ARM
D11.1.2 'The system counter', I did not find any language that
suggested the counter saturates the register width before rolling
over. So, it may be paranoid, but I presumed it to be safer to wrap
within the guaranteed interval rather than assume the sanity of the
system counter implementation. That being said, fine with rounding up
instead, so long as we don't believe there's any chance of hardware
doing something crazy.

--
Thanks,
Oliver
> Thanks,
>
>         M.
>
> --
> Without deviation from the norm, progress is not possible.

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

* [tip: timers/core] clocksource/drivers/arm_arch_timer: Fix masking for high freq counters
  2021-08-07 19:14 [PATCH v2] clocksource/arm_arch_timer: Fix masking for high freq counters Oliver Upton
  2021-08-07 22:30 ` Linus Walleij
  2021-08-09 11:07 ` Marc Zyngier
@ 2021-10-24 15:39 ` tip-bot2 for Oliver Upton
  2 siblings, 0 replies; 10+ messages in thread
From: tip-bot2 for Oliver Upton @ 2021-10-24 15:39 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Marc Zyngier, Oliver Upton, Linus Walleij, Daniel Lezcano, x86,
	linux-kernel

The following commit has been merged into the timers/core branch of tip:

Commit-ID:     c1153d52c4140424a5e31a5916fca3edd91fe13a
Gitweb:        https://git.kernel.org/tip/c1153d52c4140424a5e31a5916fca3edd91fe13a
Author:        Oliver Upton <oupton@google.com>
AuthorDate:    Sun, 17 Oct 2021 13:42:20 +01:00
Committer:     Daniel Lezcano <daniel.lezcano@linaro.org>
CommitterDate: Mon, 18 Oct 2021 09:20:02 +02:00

clocksource/drivers/arm_arch_timer: Fix masking for high freq counters

Unfortunately, the architecture provides no means to determine the bit
width of the system counter. However, we do know the following from the
specification:

 - the system counter is at least 56 bits wide
 - Roll-over time of not less than 40 years

To date, the arch timer driver has depended on the first property,
assuming any system counter to be 56 bits wide and masking off the rest.
However, combining a narrow clocksource mask with a high frequency
counter could result in prematurely wrapping the system counter by a
significant margin. For example, a 56 bit wide, 1GHz system counter
would wrap in a mere 2.28 years!

This is a problem for two reasons: v8.6+ implementations are required to
provide a 64 bit, 1GHz system counter. Furthermore, before v8.6,
implementers may select a counter frequency of their choosing.

Fix the issue by deriving a valid clock mask based on the second
property from above. Set the floor at 56 bits, since we know no system
counter is narrower than that.

[maz: fixed width computation not to lose the last bit, added
      max delta generation for the timer]

Suggested-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Oliver Upton <oupton@google.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20210807191428.3488948-1-oupton@google.com
Link: https://lore.kernel.org/r/20211017124225.3018098-13-maz@kernel.org
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
---
 drivers/clocksource/arm_arch_timer.c | 34 +++++++++++++++++++++++----
 1 file changed, 29 insertions(+), 5 deletions(-)

diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 6e20bc1..9a04eac 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -52,6 +52,12 @@
 #define CNTV_CVAL_LO	0x30
 #define CNTV_CTL	0x3c
 
+/*
+ * The minimum amount of time a generic counter is guaranteed to not roll over
+ * (40 years)
+ */
+#define MIN_ROLLOVER_SECS	(40ULL * 365 * 24 * 3600)
+
 static unsigned arch_timers_present __initdata;
 
 struct arch_timer {
@@ -96,6 +102,22 @@ static int __init early_evtstrm_cfg(char *buf)
 early_param("clocksource.arm_arch_timer.evtstrm", early_evtstrm_cfg);
 
 /*
+ * Makes an educated guess at a valid counter width based on the Generic Timer
+ * specification. Of note:
+ *   1) the system counter is at least 56 bits wide
+ *   2) a roll-over time of not less than 40 years
+ *
+ * See 'ARM DDI 0487G.a D11.1.2 ("The system counter")' for more details.
+ */
+static int arch_counter_get_width(void)
+{
+	u64 min_cycles = MIN_ROLLOVER_SECS * arch_timer_rate;
+
+	/* guarantee the returned width is within the valid range */
+	return clamp_val(ilog2(min_cycles - 1) + 1, 56, 64);
+}
+
+/*
  * Architected system timer support.
  */
 
@@ -212,13 +234,11 @@ static struct clocksource clocksource_counter = {
 	.id	= CSID_ARM_ARCH_COUNTER,
 	.rating	= 400,
 	.read	= arch_counter_read,
-	.mask	= CLOCKSOURCE_MASK(56),
 	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
 static struct cyclecounter cyclecounter __ro_after_init = {
 	.read	= arch_counter_read_cc,
-	.mask	= CLOCKSOURCE_MASK(56),
 };
 
 struct ate_acpi_oem_info {
@@ -790,7 +810,7 @@ static u64 __arch_timer_check_delta(void)
 		return CLOCKSOURCE_MASK(32);
 	}
 #endif
-	return CLOCKSOURCE_MASK(56);
+	return CLOCKSOURCE_MASK(arch_counter_get_width());
 }
 
 static void __arch_timer_setup(unsigned type,
@@ -1035,6 +1055,7 @@ struct arch_timer_kvm_info *arch_timer_get_kvm_info(void)
 static void __init arch_counter_register(unsigned type)
 {
 	u64 start_count;
+	int width;
 
 	/* Register the CP15 based counter if we have one */
 	if (type & ARCH_TIMER_TYPE_CP15) {
@@ -1059,6 +1080,10 @@ static void __init arch_counter_register(unsigned type)
 		arch_timer_read_counter = arch_counter_get_cntvct_mem;
 	}
 
+	width = arch_counter_get_width();
+	clocksource_counter.mask = CLOCKSOURCE_MASK(width);
+	cyclecounter.mask = CLOCKSOURCE_MASK(width);
+
 	if (!arch_counter_suspend_stop)
 		clocksource_counter.flags |= CLOCK_SOURCE_SUSPEND_NONSTOP;
 	start_count = arch_timer_read_counter();
@@ -1068,8 +1093,7 @@ static void __init arch_counter_register(unsigned type)
 	timecounter_init(&arch_timer_kvm_info.timecounter,
 			 &cyclecounter, start_count);
 
-	/* 56 bits minimum, so we assume worst case rollover */
-	sched_clock_register(arch_timer_read_counter, 56, arch_timer_rate);
+	sched_clock_register(arch_timer_read_counter, width, arch_timer_rate);
 }
 
 static void arch_timer_stop(struct clock_event_device *clk)

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

end of thread, other threads:[~2021-10-24 15:40 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-07 19:14 [PATCH v2] clocksource/arm_arch_timer: Fix masking for high freq counters Oliver Upton
2021-08-07 22:30 ` Linus Walleij
2021-08-08  1:14   ` Oliver Upton
2021-08-08 10:40     ` Marc Zyngier
2021-08-08 19:01       ` Oliver Upton
2021-08-09 10:45         ` Marc Zyngier
2021-08-09 15:08           ` Oliver Upton
2021-08-08 10:29   ` Marc Zyngier
2021-08-09 11:07 ` Marc Zyngier
2021-10-24 15:39 ` [tip: timers/core] clocksource/drivers/arm_arch_timer: " tip-bot2 for Oliver Upton

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).