linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] Use Tegra's microsecond counter for udelay()
@ 2014-05-20 15:36 Peter De Schrijver
  2014-05-20 15:36 ` [PATCH 1/3] kernel: add calibration_delay_done() Peter De Schrijver
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Peter De Schrijver @ 2014-05-20 15:36 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Daniel Lezcano, Thomas Gleixner, Stephen Warren,
	Thierry Reding, Paul Gortmaker, linux-arm-kernel, linux-kernel,
	linux-tegra

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

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                    |   12 ++++++++++++
 3 files changed, 47 insertions(+), 4 deletions(-)

-- 
1.7.7.rc0.72.g4b5ea.dirty


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

* [PATCH 1/3] kernel: add calibration_delay_done()
  2014-05-20 15:36 [PATCH 0/3] Use Tegra's microsecond counter for udelay() Peter De Schrijver
@ 2014-05-20 15:36 ` Peter De Schrijver
  2014-05-20 17:41   ` Sergei Shtylyov
  2014-05-20 15:36 ` [PATCH 2/3] ARM: choose highest resolution delay timer Peter De Schrijver
  2014-05-20 15:36 ` [PATCH 3/3] clocksource: tegra: Use uS counter as " Peter De Schrijver
  2 siblings, 1 reply; 7+ messages in thread
From: Peter De Schrijver @ 2014-05-20 15:36 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Daniel Lezcano, Thomas Gleixner, Stephen Warren,
	Thierry Reding, Paul Gortmaker, linux-arm-kernel, linux-kernel,
	linux-tegra

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 <pdeschrijver@nvidia.com>
---
 init/calibrate.c |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/init/calibrate.c b/init/calibrate.c
index 520702d..31cae76 100644
--- a/init/calibrate.c
+++ b/init/calibrate.c
@@ -262,6 +262,16 @@ 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)
+{
+	return;
+}
+
 void calibrate_delay(void)
 {
 	unsigned long lpj;
@@ -301,4 +311,6 @@ void calibrate_delay(void)
 
 	loops_per_jiffy = lpj;
 	printed = true;
+
+	calibration_delay_done();
 }
-- 
1.7.7.rc0.72.g4b5ea.dirty


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

* [PATCH 2/3] ARM: choose highest resolution delay timer
  2014-05-20 15:36 [PATCH 0/3] Use Tegra's microsecond counter for udelay() Peter De Schrijver
  2014-05-20 15:36 ` [PATCH 1/3] kernel: add calibration_delay_done() Peter De Schrijver
@ 2014-05-20 15:36 ` Peter De Schrijver
  2014-05-20 15:36 ` [PATCH 3/3] clocksource: tegra: Use uS counter as " Peter De Schrijver
  2 siblings, 0 replies; 7+ messages in thread
From: Peter De Schrijver @ 2014-05-20 15:36 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Daniel Lezcano, Thomas Gleixner, Stephen Warren,
	Thierry Reding, Paul Gortmaker, linux-arm-kernel, linux-kernel,
	linux-tegra

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 <pdeschrijver@nvidia.com>
---
 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 <will.deacon@arm.com>
  */
 
+#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


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

* [PATCH 3/3] clocksource: tegra: Use uS counter as delay timer
  2014-05-20 15:36 [PATCH 0/3] Use Tegra's microsecond counter for udelay() Peter De Schrijver
  2014-05-20 15:36 ` [PATCH 1/3] kernel: add calibration_delay_done() Peter De Schrijver
  2014-05-20 15:36 ` [PATCH 2/3] ARM: choose highest resolution delay timer Peter De Schrijver
@ 2014-05-20 15:36 ` Peter De Schrijver
  2014-05-20 18:37   ` Stephen Warren
  2014-05-22 13:56   ` Thierry Reding
  2 siblings, 2 replies; 7+ messages in thread
From: Peter De Schrijver @ 2014-05-20 15:36 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Daniel Lezcano, Thomas Gleixner, Stephen Warren,
	Thierry Reding, Paul Gortmaker, linux-arm-kernel, linux-kernel,
	linux-tegra

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

Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
---
 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..ed49a0b 100644
--- a/drivers/clocksource/tegra20_timer.c
+++ b/drivers/clocksource/tegra20_timer.c
@@ -28,6 +28,7 @@
 #include <linux/of_irq.h>
 #include <linux/sched_clock.h>
 
+#include <asm/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


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

* Re: [PATCH 1/3] kernel: add calibration_delay_done()
  2014-05-20 15:36 ` [PATCH 1/3] kernel: add calibration_delay_done() Peter De Schrijver
@ 2014-05-20 17:41   ` Sergei Shtylyov
  0 siblings, 0 replies; 7+ messages in thread
From: Sergei Shtylyov @ 2014-05-20 17:41 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Stephen Warren, Daniel Lezcano, linux-kernel,
	Paul Gortmaker, Thierry Reding, linux-tegra, Thomas Gleixner,
	linux-arm-kernel

On 05/20/2014 07:36 PM, Peter De Schrijver wrote:

> 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 <pdeschrijver@nvidia.com>
> ---
>   init/calibrate.c |   12 ++++++++++++
>   1 files changed, 12 insertions(+), 0 deletions(-)

> diff --git a/init/calibrate.c b/init/calibrate.c
> index 520702d..31cae76 100644
> --- a/init/calibrate.c
> +++ b/init/calibrate.c
> @@ -262,6 +262,16 @@ 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)
> +{
> +	return;

    Not really needed.

> +}
> +
>   void calibrate_delay(void)
>   {
>   	unsigned long lpj;

WBR, Sergei


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

* Re: [PATCH 3/3] clocksource: tegra: Use uS counter as delay timer
  2014-05-20 15:36 ` [PATCH 3/3] clocksource: tegra: Use uS counter as " Peter De Schrijver
@ 2014-05-20 18:37   ` Stephen Warren
  2014-05-22 13:56   ` Thierry Reding
  1 sibling, 0 replies; 7+ messages in thread
From: Stephen Warren @ 2014-05-20 18:37 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Daniel Lezcano, Thomas Gleixner, Thierry Reding,
	Paul Gortmaker, linux-arm-kernel, linux-kernel, linux-tegra

On 05/20/2014 09:36 AM, Peter De Schrijver wrote:
> All Tegra SoCs have a freerunning microsecond counter which can be used as a
> delay timer.

Patch 3 looks fine to me. I'll be happy to apply it once the other
patches are applied (or ack it or create a topic branch containing all 3
if needed, so it can be applied without waiting for dependencies to
filter up to Linus).

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

* Re: [PATCH 3/3] clocksource: tegra: Use uS counter as delay timer
  2014-05-20 15:36 ` [PATCH 3/3] clocksource: tegra: Use uS counter as " Peter De Schrijver
  2014-05-20 18:37   ` Stephen Warren
@ 2014-05-22 13:56   ` Thierry Reding
  1 sibling, 0 replies; 7+ messages in thread
From: Thierry Reding @ 2014-05-22 13:56 UTC (permalink / raw)
  To: Peter De Schrijver
  Cc: Russell King, Daniel Lezcano, Thomas Gleixner, Stephen Warren,
	Paul Gortmaker, linux-arm-kernel, linux-kernel, linux-tegra

[-- Attachment #1: Type: text/plain, Size: 61 bytes --]

In the subject: s/uS/us/; S == Siemens, s == second

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

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

end of thread, other threads:[~2014-05-22 13:59 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-20 15:36 [PATCH 0/3] Use Tegra's microsecond counter for udelay() Peter De Schrijver
2014-05-20 15:36 ` [PATCH 1/3] kernel: add calibration_delay_done() Peter De Schrijver
2014-05-20 17:41   ` Sergei Shtylyov
2014-05-20 15:36 ` [PATCH 2/3] ARM: choose highest resolution delay timer Peter De Schrijver
2014-05-20 15:36 ` [PATCH 3/3] clocksource: tegra: Use uS counter as " Peter De Schrijver
2014-05-20 18:37   ` Stephen Warren
2014-05-22 13:56   ` Thierry Reding

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