Skip to contentSkip to conversation

A7/A15 architected timer support

PATCH Superseded Marc Zyngier 4 participants 13 messages Apr 16, 2012 – Apr 19, 2012

Subsystems (5)

v3 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

v3 cover A7/A15 architected timer support

This patch series adds support for the architected timers found in Cortex-A7 and Cortex-A15. It adds local timer support, sched_clock, global timer and DT support.

Tested on Cortex A15, based on v3.4-rc3. Branch also available at:
git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git timers-v3.4-rc3

* From v2:
- Allow the generic code to report that local timers cannot be used.
- Plug local timers into the VExpress DT code.

* From the initial revision:
- Fixed global timer registration when an SMP kernel is running on UP with LOCAL_TIMERS enabled.

Marc Zyngier (6):
ARM: local timers: reserve local_timer_register() to SMP
ARM: local timers: Add A15 architected timer support
ARM: architected timers: Add A15 specific sched_clock implementation
ARM: architected timers: add DT support
ARM: architected timers: add support for UP timer
ARM: vexpress: plug local timers into the DT code

 .../devicetree/bindings/arm/arch_timer.txt         |   27 ++
 arch/arm/Kconfig                                   |    7 +
 arch/arm/include/asm/arch_timer.h                  |   31 ++
 arch/arm/kernel/Makefile                           |    1 +
 arch/arm/kernel/arch_timer.c                       |  364 ++++++++++++++++++++
 arch/arm/kernel/smp.c                              |    3 +
 arch/arm/mach-vexpress/v2m.c                       |    8 +-
 7 files changed, 440 insertions(+), 1 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/arch_timer.txt
 create mode 100644 arch/arm/include/asm/arch_timer.h
 create mode 100644 arch/arm/kernel/arch_timer.c
Signature · 1 line
1.7.7.1
#1 lore raw

PATCH v3 1/6 ARM: local timers: reserve local_timer_register() to SMP

When running an SMP_ON_UP enabled kernel on UP, or with nosmp passed to the kernel, we want to be able to detect that a local timer is not going to be used (local timers are only used on SMP platforms), so we could register it as a global timer instead.

Return -ENXIO when the above case is detected.

---
 arch/arm/kernel/smp.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)
arch/arm/kernel/smp.c +3 -0
index addbbe8..11c4148 100644
@@ -454,6 +454,9 @@ static struct local_timer_ops *lt_ops;
 #ifdef CONFIG_LOCAL_TIMERS
 int local_timer_register(struct local_timer_ops *ops)
 {
+	if (!is_smp() || !setup_max_cpus)
+		return -ENXIO;
+
 	if (lt_ops)
 		return -EBUSY;
 
Signature · 1 line
1.7.7.1
#2 lore raw

PATCH v3 2/6 ARM: local timers: Add A15 architected timer support

In reply to Marc Zyngier

Add support for the A15 generic timer and clocksource. As the timer generates interrupts on a different PPI depending on the execution mode (normal or secure), it is possible to register two different PPIs.

---
 arch/arm/Kconfig                  |    7 +
 arch/arm/include/asm/arch_timer.h |   19 +++
 arch/arm/kernel/Makefile          |    1 +
 arch/arm/kernel/arch_timer.c      |  287 +++++++++++++++++++++++++++++++++++++
 4 files changed, 314 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/include/asm/arch_timer.h
 create mode 100644 arch/arm/kernel/arch_timer.c
arch/arm/Kconfig +7 -0
index cf006d4..68c382d 100644
@@ -1543,6 +1543,13 @@ config HAVE_ARM_SCU
 	help
 	  This option enables support for the ARM system coherency unit
 
+config ARM_ARCH_TIMER
+	bool "Architected timer support"
+	depends on CPU_V7
+	select TICK_ONESHOT
+	help
+	  This option enables support for the ARM architected timer
+
 config HAVE_ARM_TWD
 	bool
 	depends on SMP
arch/arm/include/asm/arch_timer.h new file +19 -0
new file mode 100644
index 0000000..827305d
@@ -0,0 +1,19 @@
+#ifndef __ASMARM_ARCH_TIMER_H
+#define __ASMARM_ARCH_TIMER_H
+
+#include <linux/ioport.h>
+
+struct arch_timer {
+	struct resource	res[2];
+};
+
+#ifdef CONFIG_ARM_ARCH_TIMER
+int arch_timer_register(struct arch_timer *);
+#else
+static inline int arch_timer_register(struct arch_timer *at)
+{
+	return -ENXIO;
+}
+#endif
+
+#endif
arch/arm/kernel/Makefile +1 -0
index 7b787d6..22b0f1e 100644
@@ -34,6 +34,7 @@ obj-$(CONFIG_ARM_CPU_SUSPEND)	+= sleep.o suspend.o
 obj-$(CONFIG_SMP)		+= smp.o smp_tlb.o
 obj-$(CONFIG_HAVE_ARM_SCU)	+= smp_scu.o
 obj-$(CONFIG_HAVE_ARM_TWD)	+= smp_twd.o
+obj-$(CONFIG_ARM_ARCH_TIMER)	+= arch_timer.o
 obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o insn.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o insn.o
 obj-$(CONFIG_JUMP_LABEL)	+= jump_label.o insn.o patch.o
arch/arm/kernel/arch_timer.c new file +287 -0

287 lines not on this page · raw message

Signature · 1 line
1.7.7.1
#3 lore raw

PATCH v3 2/6 ARM: local timers: Add A15 architected timer support

arch/arm/Kconfig config HAVE_ARM_SCU · line 1549

Quoted 12 lines · Marc Zyngier
arch/arm/Kconfig +4 -0
index cf006d4..68c382d 100644
@@ -1543,6 +1543,13 @@ config HAVE_ARM_SCU
 	help
 	  This option enables support for the ARM system coherency unit
 
+config ARM_ARCH_TIMER
+	bool "Architected timer support"
+	depends on CPU_V7
+	select TICK_ONESHOT

I believe TICK_ONESHOT is a "hidden" option that should not be selected outside the generic clockevents layer. It seems Russell and Thomas have talked about this too, see 3872c48 (tick: Document TICK_ONESHOT config option, 2012-03-31).

Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
#4 lore raw

PATCH v3 2/6 ARM: local timers: Add A15 architected timer support

On 16/04/12 18:45, Stephen Boyd wrote:

Hi Stephen,

Quoted 9 lines · Marc Zyngier
Quoted 8 lines
arch/arm/Kconfig +0 -0
index cf006d4..68c382d 100644
@@ -1543,6 +1543,13 @@ config HAVE_ARM_SCU
 	help
 	  This option enables support for the ARM system coherency unit
 
Quoted 9 lines

arch/arm/Kconfig config HAVE_ARM_SCU · line 1549

Quoted 4 lines
arch/arm/Kconfig +4 -0
+config ARM_ARCH_TIMER
+	bool "Architected timer support"
+	depends on CPU_V7
+	select TICK_ONESHOT

I believe TICK_ONESHOT is a "hidden" option that should not be selected outside the generic clockevents layer. It seems Russell and Thomas have talked about this too, see 3872c48 (tick: Document TICK_ONESHOT config option, 2012-03-31).

Ah, thanks for noticing this. I'm glad this point has been clarified. I'll push a fix.

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#5 lore raw

PATCH v3 3/6 ARM: architected timers: Add A15 specific sched_clock implementation

In reply to Marc Zyngier

Provide an A15 sched_clock implementation using the virtual counter, which is thought to be more useful than the physical one in a virtualised environment, as it can offset the time spent in another VM or the hypervisor.

---
 arch/arm/include/asm/arch_timer.h |    6 ++++++
 arch/arm/kernel/arch_timer.c      |   25 +++++++++++++++++++++++++
 2 files changed, 31 insertions(+), 0 deletions(-)
arch/arm/include/asm/arch_timer.h +6 -0
index 827305d..dc008c6 100644
@@ -9,11 +9,17 @@ struct arch_timer {
 
 #ifdef CONFIG_ARM_ARCH_TIMER
 int arch_timer_register(struct arch_timer *);
+int arch_timer_sched_clock_init(void);
 #else
 static inline int arch_timer_register(struct arch_timer *at)
 {
 	return -ENXIO;
 }
+
+static inline int arch_timer_sched_clock_init(void)
+{
+	return -ENXIO;
+}
 #endif
 
 #endif
arch/arm/kernel/arch_timer.c +25 -0
index ce8c7ed..611859a 100644
@@ -22,6 +22,7 @@
 #include <asm/cputype.h>
 #include <asm/localtimer.h>
 #include <asm/arch_timer.h>
+#include <asm/sched_clock.h>
 
 static unsigned long arch_timer_rate;
 static int arch_timer_ppi;
@@ -203,6 +204,18 @@ static inline cycle_t arch_counter_get_cntvct(void)
 	return ((cycle_t) cvalh << 32) | cvall;
 }
 
+static u32 notrace arch_counter_get_cntvct32(void)
+{
+	cycle_t cntvct = arch_counter_get_cntvct();
+
+	/*
+	 * The sched_clock infrastructure only knows about counters
+	 * with@most 32bits. Forget about the upper 24 bits for the
+	 * time being...
+	 */
+	return (u32)(cntvct & (u32)~0);
+}
+
 static cycle_t arch_counter_read(struct clocksource *cs)
 {
 	return arch_counter_get_cntpct();
@@ -285,3 +298,15 @@ out_free:
 
 	return err;
 }
+
+int __init arch_timer_sched_clock_init(void)
+{
+	int err;
+
+	err = arch_timer_available();
+	if (err)
+		return err;
+
+	setup_sched_clock(arch_counter_get_cntvct32, 32, arch_timer_rate);
+	return 0;
+}
Signature · 1 line
1.7.7.1
#6 lore raw

PATCH v3 4/6 ARM: architected timers: add DT support

In reply to Marc Zyngier

Add runtime DT support and documentation for the Cortex A7/A15 architected timers.

---
 .../devicetree/bindings/arm/arch_timer.txt         |   27 ++++++++++
 arch/arm/include/asm/arch_timer.h                  |    6 ++
 arch/arm/kernel/arch_timer.c                       |   53 +++++++++++++++++---
 3 files changed, 79 insertions(+), 7 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/arch_timer.txt
Documentation/devicetree/bindings/arm/arch_timer.txt new file +27 -0
new file mode 100644
index 0000000..52478c8
@@ -0,0 +1,27 @@
+* ARM architected timer
+
+ARM Cortex-A7 and Cortex-A15 have a per-core architected timer, which
+provides per-cpu timers.
+
+The timer is attached to a GIC to deliver its per-processor interrupts.
+
+** Timer node properties:
+
+- compatible : Should at least contain "arm,armv7-timer".
+
+- interrupts : Interrupt list for secure, non-secure, virtual and
+  hypervisor timers, in that order.
+
+- clock-frequency : The frequency of the main counter, in Hz. Optional.
+
+Example:
+
+	timer {
+		compatible = "arm,cortex-a15-timer",
+			     "arm,armv7-timer";
+		interrupts = <1 13 0xf08>,
+			     <1 14 0xf08>,
+			     <1 11 0xf08>,
+			     <1 10 0xf08>;
+		clock-frequency = <100000000>;
+	};
arch/arm/include/asm/arch_timer.h +6 -0
index dc008c6..935897f 100644
@@ -10,12 +10,18 @@ struct arch_timer {
 #ifdef CONFIG_ARM_ARCH_TIMER
 int arch_timer_register(struct arch_timer *);
 int arch_timer_sched_clock_init(void);
+int arch_timer_of_register(void);
 #else
 static inline int arch_timer_register(struct arch_timer *at)
 {
 	return -ENXIO;
 }
 
+static inline int arch_timer_of_register(void)
+{
+	return -ENXIO;
+}
+
 static inline int arch_timer_sched_clock_init(void)
 {
 	return -ENXIO;
arch/arm/kernel/arch_timer.c +46 -7

86 lines not on this page · raw message

Signature · 1 line
1.7.7.1
#7 lore raw

PATCH v3 4/6 ARM: architected timers: add DT support

Quoted 12 lines · Marc Zyngier

Add runtime DT support and documentation for the Cortex A7/A15 architected timers.

---
 .../devicetree/bindings/arm/arch_timer.txt         |   27 ++++++++++
 arch/arm/include/asm/arch_timer.h                  |    6 ++
 arch/arm/kernel/arch_timer.c                       |   53 +++++++++++++++++---
 3 files changed, 79 insertions(+), 7 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/arch_timer.txt

This looks good, but do we actually still need the non-DT case?

Both vexpress and exynos5 allow booting through DT and we are not planning to add any new platforms with these timers that don't.

Arnd

#8 lore raw

PATCH v3 4/6 ARM: architected timers: add DT support

Quoted 14 lines · Arnd Bergmann
Quoted 12 lines · Marc Zyngier

Add runtime DT support and documentation for the Cortex A7/A15 architected timers.

---
 .../devicetree/bindings/arm/arch_timer.txt         |   27 ++++++++++
 arch/arm/include/asm/arch_timer.h                  |    6 ++
 arch/arm/kernel/arch_timer.c                       |   53 +++++++++++++++++---
 3 files changed, 79 insertions(+), 7 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/arch_timer.txt
Quoted 4 lines

This looks good, but do we actually still need the non-DT case?

Both vexpress and exynos5 allow booting through DT and we are not planning to add any new platforms with these timers that don't.

Yes, the non-DT code is a leftover from dark ages we'd rather forget. I'll remove that code for the next iteration.

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#9 lore raw

PATCH v3 5/6 ARM: architected timers: add support for UP timer

In reply to Marc Zyngier

If CONFIG_LOCAL_TIMERS is not defined, let the architected timer driver register a single clock_event_device that is used as a global timer.

---
 arch/arm/kernel/arch_timer.c |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)
arch/arm/kernel/arch_timer.c +13 -0
index e2c1f86..8062805 100644
@@ -245,6 +245,8 @@ static struct local_timer_ops arch_timer_ops __cpuinitdata = {
 	.stop	= arch_timer_stop,
 };
 
+static struct clock_event_device arch_timer_global_evt;
+
 static int __init arch_timer_common_register(void)
 {
 	int err;
@@ -279,6 +281,17 @@ static int __init arch_timer_common_register(void)
 	}
 
 	err = local_timer_register(&arch_timer_ops);
+	if (err) {
+		/*
+		 * We couldn't register as a local timer (could be
+		 * because we're on a UP platform, or because some
+		 * other local timer is already present...). Try as a
+		 * global timer instead.
+		 */
+		arch_timer_global_evt.cpumask = cpumask_of(0);
+		err = arch_timer_setup(&arch_timer_global_evt);
+	}
+
 	if (err)
 		goto out_free_irq;
 
Signature · 1 line
1.7.7.1
#10 lore raw

PATCH v3 6/6 ARM: vexpress: plug local timers into the DT code

In reply to Marc Zyngier
---
 arch/arm/mach-vexpress/v2m.c |    8 +++++++-
 1 files changed, 7 insertions(+), 1 deletions(-)
arch/arm/mach-vexpress/v2m.c +7 -1
index 47cdcca..fd62bfe 100644
@@ -19,8 +19,10 @@
 #include <linux/clkdev.h>
 #include <linux/mtd/physmap.h>
 
+#include <asm/arch_timer.h>
 #include <asm/mach-types.h>
 #include <asm/sizes.h>
+#include <asm/smp_twd.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
@@ -616,7 +618,6 @@ void __init v2m_dt_init_early(void)
 	}
 
 	clkdev_add_table(v2m_dt_lookups, ARRAY_SIZE(v2m_dt_lookups));
-	versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
 }
 
 static  struct of_device_id vexpress_irq_match[] __initdata = {
@@ -643,6 +644,11 @@ static void __init v2m_dt_timer_init(void)
 		return;
 	node = of_find_node_by_path(path);
 	v2m_sp804_init(of_iomap(node, 0), irq_of_parse_and_map(node, 0));
+	if (arch_timer_of_register())
+		twd_local_timer_of_register();
+
+	if (arch_timer_sched_clock_init())
+		versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
 }
 
 static struct sys_timer v2m_dt_timer = {
Signature · 1 line
1.7.7.1
#11 lore raw

PATCH v3 6/6 ARM: vexpress: plug local timers into the DT code

arch/arm/mach-vexpress/v2m.c static void __init v2m_dt_timer_init(void) · line 652

Quoted 10 lines · Marc Zyngier
arch/arm/mach-vexpress/v2m.c +5 -0
@@ -643,6 +644,11 @@ static void __init v2m_dt_timer_init(void)
 		return;
 	node = of_find_node_by_path(path);
 	v2m_sp804_init(of_iomap(node, 0), irq_of_parse_and_map(node, 0));
+	if (arch_timer_of_register())
+		twd_local_timer_of_register();
+
+	if (arch_timer_sched_clock_init())
+		versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
 }

My personal preference would be "if (arch_timer*() != 0)" here - obviously makes no difference, but clearly states the idea, but anyway looks good to me.

Cheers!

Pawe?

#12 lore raw

PATCH v3 6/6 ARM: vexpress: plug local timers into the DT code

Quoted 15 lines · Pawel Moll

arch/arm/mach-vexpress/v2m.c static void __init v2m_dt_timer_init(void) · line 652

Quoted 10 lines · Marc Zyngier
arch/arm/mach-vexpress/v2m.c +5 -0
@@ -643,6 +644,11 @@ static void __init v2m_dt_timer_init(void)
 		return;
 	node = of_find_node_by_path(path);
 	v2m_sp804_init(of_iomap(node, 0), irq_of_parse_and_map(node, 0));
+	if (arch_timer_of_register())
+		twd_local_timer_of_register();
+
+	if (arch_timer_sched_clock_init())
+		versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
 }

My personal preference would be "if (arch_timer*() != 0)" here - obviously makes no difference, but clearly states the idea, but anyway looks good to me.

Fair enough.

Quoted 1 line

Thanks Pawe?.

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...