2014-06-12 15:58:46

by Peter De Schrijver

[permalink] [raw]
Subject: [PATCH 0/3] Use Tegra's microsecond counter for udelay()

This patchset introduces support for Tegra's microsecond counter as the
udelay() timer. This is useful on Tegra SoCs which do not have an arch timer
such as Tegra20 and Tegra30. Using the microsecond counter instead of a delay
based loop avoids potential problems during cpu frequency changes.

The set consists of 3 patches:

Patch 1 introduces a new call which is used by the ARM architecture delay
timer code to prevent changing the delay timer after calibration is finished
and thus can be in use.

Patch 2 adds logic to choose the delay timer with the highest resolution. This
allows the same registration code to be used on all Tegra SoCs and yet use the
higher resolution arch timer when available (eg on Tegra114 or Tegra124).

Patch 3 adds the actual delay timer code.

Patch set has been verified on ventana (Tegra20), beaver (Tegra30),
dalmore (Tegra114) and jetson TK1 (Tegra124).

Changes since v1:
* Address review comments

What needs to be done to make progress on this one? I think it's really useful
to have this when CPU DVFS is available.

Peter De Schrijver (3):
kernel: add calibration_delay_done()
ARM: choose highest resolution delay timer
clocksource: tegra: Use us counter as delay timer

arch/arm/lib/delay.c | 26 ++++++++++++++++++++++----
drivers/clocksource/tegra20_timer.c | 13 +++++++++++++
init/calibrate.c | 11 +++++++++++
3 files changed, 46 insertions(+), 4 deletions(-)

--
1.7.7.rc0.72.g4b5ea.dirty


2014-06-12 15:58:55

by Peter De Schrijver

[permalink] [raw]
Subject: [PATCH v2 1/3] kernel: add calibration_delay_done()

Add calibration_delay_done() call and dummy implementation. This allows
architectures to stop accepting registrations for new timer based delay
functions.

Signed-off-by: Peter De Schrijver <[email protected]>
---
init/calibrate.c | 11 +++++++++++
1 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/init/calibrate.c b/init/calibrate.c
index 520702d..ce635dc 100644
--- a/init/calibrate.c
+++ b/init/calibrate.c
@@ -262,6 +262,15 @@ unsigned long __attribute__((weak)) calibrate_delay_is_known(void)
return 0;
}

+/*
+ * Indicate the cpu delay calibration is done. This can be used by
+ * architectures to stop accepting delay timer registrations after this point.
+ */
+
+void __attribute__((weak)) calibration_delay_done(void)
+{
+}
+
void calibrate_delay(void)
{
unsigned long lpj;
@@ -301,4 +310,6 @@ void calibrate_delay(void)

loops_per_jiffy = lpj;
printed = true;
+
+ calibration_delay_done();
}
--
1.7.7.rc0.72.g4b5ea.dirty

2014-06-12 15:59:01

by Peter De Schrijver

[permalink] [raw]
Subject: [PATCH v2 2/3] ARM: choose highest resolution delay timer

In case there are several possible delay timers, choose the one with the
highest resolution. This code relies on the fact secondary CPUs have not yet
been brought online when register_current_timer_delay() is called. This is
ensured by implementing calibration_delay_done(),

Signed-off-by: Peter De Schrijver <[email protected]>
---
arch/arm/lib/delay.c | 26 ++++++++++++++++++++++----
1 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/arch/arm/lib/delay.c b/arch/arm/lib/delay.c
index 5306de3..312d43e 100644
--- a/arch/arm/lib/delay.c
+++ b/arch/arm/lib/delay.c
@@ -19,6 +19,7 @@
* Author: Will Deacon <[email protected]>
*/

+#include <linux/clocksource.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -36,6 +37,7 @@ struct arm_delay_ops arm_delay_ops = {

static const struct delay_timer *delay_timer;
static bool delay_calibrated;
+static u64 delay_res;

int read_current_timer(unsigned long *timer_val)
{
@@ -47,6 +49,11 @@ int read_current_timer(unsigned long *timer_val)
}
EXPORT_SYMBOL_GPL(read_current_timer);

+static inline u64 cyc_to_ns(u64 cyc, u32 mult, u32 shift)
+{
+ return (cyc * mult) >> shift;
+}
+
static void __timer_delay(unsigned long cycles)
{
cycles_t start = get_cycles();
@@ -69,18 +76,24 @@ static void __timer_udelay(unsigned long usecs)

void __init register_current_timer_delay(const struct delay_timer *timer)
{
- if (!delay_calibrated) {
- pr_info("Switching to timer-based delay loop\n");
+ u32 new_mult, new_shift;
+ u64 res;
+
+ clocks_calc_mult_shift(&new_mult, &new_shift, timer->freq,
+ NSEC_PER_SEC, 3600);
+ res = cyc_to_ns(1ULL, new_mult, new_shift);
+
+ if (!delay_calibrated && (!delay_res || (res < delay_res))) {
+ pr_info("Switching to timer-based delay loop, resolution %lluns\n", res);
delay_timer = timer;
lpj_fine = timer->freq / HZ;
+ delay_res = res;

/* cpufreq may scale loops_per_jiffy, so keep a private copy */
arm_delay_ops.ticks_per_jiffy = lpj_fine;
arm_delay_ops.delay = __timer_delay;
arm_delay_ops.const_udelay = __timer_const_udelay;
arm_delay_ops.udelay = __timer_udelay;
-
- delay_calibrated = true;
} else {
pr_info("Ignoring duplicate/late registration of read_current_timer delay\n");
}
@@ -91,3 +104,8 @@ unsigned long calibrate_delay_is_known(void)
delay_calibrated = true;
return lpj_fine;
}
+
+void calibration_delay_done(void)
+{
+ delay_calibrated = true;
+}
--
1.7.7.rc0.72.g4b5ea.dirty

2014-06-12 15:59:10

by Peter De Schrijver

[permalink] [raw]
Subject: [PATCH v2 3/3] clocksource: tegra: Use us counter as delay timer

All Tegra SoCs have a freerunning microsecond counter which can be used as a
delay timer.

Signed-off-by: Peter De Schrijver <[email protected]>
---
drivers/clocksource/tegra20_timer.c | 13 +++++++++++++
1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c
index d1869f0..d2616ef 100644
--- a/drivers/clocksource/tegra20_timer.c
+++ b/drivers/clocksource/tegra20_timer.c
@@ -27,6 +27,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/sched_clock.h>
+#include <linux/delay.h>

#include <asm/mach/time.h>
#include <asm/smp_twd.h>
@@ -53,6 +54,8 @@ static void __iomem *rtc_base;
static struct timespec persistent_ts;
static u64 persistent_ms, last_persistent_ms;

+static struct delay_timer tegra_delay_timer;
+
#define timer_writel(value, reg) \
__raw_writel(value, timer_reg_base + (reg))
#define timer_readl(reg) \
@@ -139,6 +142,11 @@ static void tegra_read_persistent_clock(struct timespec *ts)
*ts = *tsp;
}

+static unsigned long tegra_delay_timer_read_counter_long(void)
+{
+ return readl(timer_reg_base + TIMERUS_CNTR_1US);
+}
+
static irqreturn_t tegra_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *evt = (struct clock_event_device *)dev_id;
@@ -206,6 +214,11 @@ static void __init tegra20_init_timer(struct device_node *np)
BUG();
}

+ tegra_delay_timer.read_current_timer =
+ tegra_delay_timer_read_counter_long;
+ tegra_delay_timer.freq = 1000000;
+ register_current_timer_delay(&tegra_delay_timer);
+
ret = setup_irq(tegra_timer_irq.irq, &tegra_timer_irq);
if (ret) {
pr_err("Failed to register timer IRQ: %d\n", ret);
--
1.7.7.rc0.72.g4b5ea.dirty

2014-06-12 19:38:33

by Stephen Warren

[permalink] [raw]
Subject: Re: [PATCH 0/3] Use Tegra's microsecond counter for udelay()

On 06/12/2014 09:58 AM, Peter De Schrijver wrote:
> This patchset introduces support for Tegra's microsecond counter as the
> udelay() timer. This is useful on Tegra SoCs which do not have an arch timer
> such as Tegra20 and Tegra30. Using the microsecond counter instead of a delay
> based loop avoids potential problems during cpu frequency changes.
>
> The set consists of 3 patches:
>
> Patch 1 introduces a new call which is used by the ARM architecture delay
> timer code to prevent changing the delay timer after calibration is finished
> and thus can be in use.
>
> Patch 2 adds logic to choose the delay timer with the highest resolution. This
> allows the same registration code to be used on all Tegra SoCs and yet use the
> higher resolution arch timer when available (eg on Tegra114 or Tegra124).
>
> Patch 3 adds the actual delay timer code.
>
> Patch set has been verified on ventana (Tegra20), beaver (Tegra30),
> dalmore (Tegra114) and jetson TK1 (Tegra124).

Russell, Paul, do patches 1 and 2 look good to you? If so, if you can
ack them, I'd be happy to queue this series in the Tegra git tree. If
that doesn't work for you, please let me know who will apply these
patches. Thanks.

> Changes since v1:
> * Address review comments

That's not a very useful description of the changes, and there's no "V2"
in the subject...

2014-06-12 22:56:17

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [PATCH 0/3] Use Tegra's microsecond counter for udelay()

On Thu, Jun 12, 2014 at 01:38:28PM -0600, Stephen Warren wrote:
> On 06/12/2014 09:58 AM, Peter De Schrijver wrote:
> > This patchset introduces support for Tegra's microsecond counter as the
> > udelay() timer. This is useful on Tegra SoCs which do not have an arch timer
> > such as Tegra20 and Tegra30. Using the microsecond counter instead of a delay
> > based loop avoids potential problems during cpu frequency changes.
> >
> > The set consists of 3 patches:
> >
> > Patch 1 introduces a new call which is used by the ARM architecture delay
> > timer code to prevent changing the delay timer after calibration is finished
> > and thus can be in use.
> >
> > Patch 2 adds logic to choose the delay timer with the highest resolution. This
> > allows the same registration code to be used on all Tegra SoCs and yet use the
> > higher resolution arch timer when available (eg on Tegra114 or Tegra124).
> >
> > Patch 3 adds the actual delay timer code.
> >
> > Patch set has been verified on ventana (Tegra20), beaver (Tegra30),
> > dalmore (Tegra114) and jetson TK1 (Tegra124).
>
> Russell, Paul, do patches 1 and 2 look good to you? If so, if you can
> ack them, I'd be happy to queue this series in the Tegra git tree. If
> that doesn't work for you, please let me know who will apply these
> patches. Thanks.

When I saw them, I did have a question in the back of my mind about
the interlocking - whether we should just mandate that these are
always registered before delay calibration. Then I remember the
mess that platforms made of the sched_clock() stuff.

So, I don't see any other way to ensure that platforms do the right
thing other than providing that kind of stick... so I guess we'll
have to have them.

Acked-by: Russell King <[email protected]>

--
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

2014-06-13 07:25:24

by Peter De Schrijver

[permalink] [raw]
Subject: Re: [PATCH 0/3] Use Tegra's microsecond counter for udelay()

On Thu, Jun 12, 2014 at 09:38:28PM +0200, Stephen Warren wrote:
> On 06/12/2014 09:58 AM, Peter De Schrijver wrote:
> > This patchset introduces support for Tegra's microsecond counter as the
> > udelay() timer. This is useful on Tegra SoCs which do not have an arch timer
> > such as Tegra20 and Tegra30. Using the microsecond counter instead of a delay
> > based loop avoids potential problems during cpu frequency changes.
> >
> > The set consists of 3 patches:
> >
> > Patch 1 introduces a new call which is used by the ARM architecture delay
> > timer code to prevent changing the delay timer after calibration is finished
> > and thus can be in use.
> >
> > Patch 2 adds logic to choose the delay timer with the highest resolution. This
> > allows the same registration code to be used on all Tegra SoCs and yet use the
> > higher resolution arch timer when available (eg on Tegra114 or Tegra124).
> >
> > Patch 3 adds the actual delay timer code.
> >
> > Patch set has been verified on ventana (Tegra20), beaver (Tegra30),
> > dalmore (Tegra114) and jetson TK1 (Tegra124).
>
> Russell, Paul, do patches 1 and 2 look good to you? If so, if you can
> ack them, I'd be happy to queue this series in the Tegra git tree. If
> that doesn't work for you, please let me know who will apply these
> patches. Thanks.
>
> > Changes since v1:
> > * Address review comments
>
> That's not a very useful description of the changes, and there's no "V2"
> in the subject...

Yes... something went wrong it seems...

2014-06-16 18:52:15

by Stephen Warren

[permalink] [raw]
Subject: Re: [PATCH 0/3] Use Tegra's microsecond counter for udelay()

On 06/12/2014 09:58 AM, Peter De Schrijver wrote:
> This patchset introduces support for Tegra's microsecond counter as the
> udelay() timer. This is useful on Tegra SoCs which do not have an arch timer
> such as Tegra20 and Tegra30. Using the microsecond counter instead of a delay
> based loop avoids potential problems during cpu frequency changes.
>
> The set consists of 3 patches:
>
> Patch 1 introduces a new call which is used by the ARM architecture delay
> timer code to prevent changing the delay timer after calibration is finished
> and thus can be in use.
>
> Patch 2 adds logic to choose the delay timer with the highest resolution. This
> allows the same registration code to be used on all Tegra SoCs and yet use the
> higher resolution arch timer when available (eg on Tegra114 or Tegra124).
>
> Patch 3 adds the actual delay timer code.
>
> Patch set has been verified on ventana (Tegra20), beaver (Tegra30),
> dalmore (Tegra114) and jetson TK1 (Tegra124).

I've applied this series to Tegra's for-3.17/delay-timer branch.