Thread (9 messages) flat view 9 messages, 2 authors, 2017-12-18

[PATCH 2/4] clocksource: stm32: use prescaler to adjust the resolution

From: Daniel Lezcano <hidden>
Date: 2017-12-18 10:54:23
Also in: lkml

On 18/12/2017 10:44, Benjamin Gaignard wrote:
2017-12-18 10:26 GMT+01:00 Daniel Lezcano [off-list ref]:
quoted
On 15/12/2017 09:52, Benjamin Gaignard wrote:
quoted
Rather than use fixed prescaler values compute it to get a clock
as close as possible of 10KHz and a resolution of 0.1ms.

Signed-off-by: Benjamin Gaignard <redacted>
---
 drivers/clocksource/timer-stm32.c | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index 23a321cca45b..de721d318065 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -37,6 +37,11 @@

 #define TIM_EGR_UG   BIT(0)

+#define MAX_TIM_PSC  0xFFFF
+
+/* Target a 10KHz clock to get a resolution of 0.1 ms */
+#define TARGETED_CLK_RATE 10000
+
 static int stm32_clock_event_shutdown(struct clock_event_device *evt)
 {
      struct timer_of *to = to_timer_of(evt);
@@ -83,7 +88,7 @@ static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id)
 static void __init stm32_clockevent_init(struct timer_of *to)
 {
      unsigned long max_delta;
-     int prescaler;
+     unsigned long prescaler;

      to->clkevt.name = "stm32_clockevent";
      to->clkevt.features = CLOCK_EVT_FEAT_PERIODIC;
@@ -96,13 +101,17 @@ static void __init stm32_clockevent_init(struct timer_of *to)
      /* Detect whether the timer is 16 or 32 bits */
      writel_relaxed(~0U, timer_of_base(to) + TIM_ARR);
      max_delta = readl_relaxed(timer_of_base(to) + TIM_ARR);
-     if (max_delta == ~0U) {
-             prescaler = 1;
+     to->clkevt.rating = 50;
+     if (max_delta == ~0U)
              to->clkevt.rating = 250;
-     } else {
-             prescaler = 1024;
-             to->clkevt.rating = 50;
-     }
+
+     /*
+      * Get the highest possible prescaler value to be as close
+      * as possible of TARGETED_CLK_RATE
+      */
+     prescaler = DIV_ROUND_CLOSEST(timer_of_rate(to), TARGETED_CLK_RATE);
With a 90MHz or 125MHz, the prescaler will be 9000 or 12500, so much
more than the 1024 we have today for 16b, and 1 for 32b.

Shouldn't the computation be weighted with the bits width ?
My goal was to get the same resolution (0.1ms) for all the timers so
the wrap will depend of the number of bits like you describe below.
Do you really want 1ms resolution with a 32bits timer ?
quoted
Otherwise the timer will wrap like:

32bits:

before: (2^32 / 90e6) x 1 = 47.72 seconds
after:  (2^32 / 90e6) x 9000 = 119.3 *hours* ~= 5days

16bits:

before: (2^16 / 90e6) x 1024 = 0.745 seconds
after:  (2^16 / 90e6) x 9000 = 6.55 seconds

The patch is ok to target the 10KHz timer rate for 16b with a 1ms
resolution wrapping up after 6.55 seconds. But not for the 32bits timer.
Furthermore, we can't tell anymore the 32bits timers have a rating of
250 after this patch.
What is the link between rating and resolution (or wrap) ?
Low resolution => hardly suitable for real use case => bad rating.
From include/linux/clocksource.h
[ ... ]

 *                      100-199: Base level usability.
 *                              Functional for real use, but not desired.
 *                      200-299: Good.
 *                              A correct and usable clocksource.

[ ... ]

If you want to set a timer with a delta of 12.345ms and the resolution
is 1ms. Then you end up with a timer expiring after 13ms.
Is it a problem to get a long wrap ?
It is not a problem to go for a long wrap, it is usually interesting
when the CPU has deep idle states. But it is not worth to sacrifice the
resolution with the 32bits timer in order to have 5 days before wrap.

Keeping 47secs is fine for the moment. If you want a coarser grain, that
could be acceptable because the resolution is very high but we can
postpone that for later after solving this 16b / 32b thing.
quoted
Leave the 32bits part as it is and compute the prescaler only in case of
16bits with the target rate, which sounds a reasonable approach.
quoted
+     if (prescaler > MAX_TIM_PSC)
+             prescaler = MAX_TIM_PSC;
That can happen only if the clock rate is greater than ~655MHz, that
could not happen today as far as I can tell regarding the DT. So if we
hit this condition, we should speak up in the log (pr_warn).
It is to be futur proof for next possible SoC but even if prescaler
reach this limit
it is not a problem the only consequence would be that resolution and
wrap change.
Got that, but that needs to be logged with a pr_warn or pr_info.
quoted
quoted
      writel_relaxed(0, timer_of_base(to) + TIM_ARR);
      writel_relaxed(prescaler - 1, timer_of_base(to) + TIM_PSC);
Can you fix this prescaler - 1 in order to be consistent with the
computation with 16b ? (32b prescaler = 0, 16b prescaler = clk_rate /
target ).
In the hardware the clock is divise by " TIM_PSC value  1" so to be coherent
with that I need to do prescaler -1.
Ah, ok.


-- 
 <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help