Skip to contentSkip to conversation

Make SMP timers standalone

PATCH Superseded Marc Zyngier 8 participants 40 messages Dec 22, 2011 – Jan 5, 2012

Subsystems (11)
lore
Share & tools
lore
#0 lore raw

v2 cover Make SMP timers standalone

The LOCAL_TIMERS infrastructure has a few limitations:
- It only allows one implementation to be compiled in, hence preventing a single kernel image to be booted on hardware with different requirements (Tegra and MSM, for example).
- It is only supported on SMP, which is a problem on platforms where the local timer can be used on UP platforms (Cortex A15 being one).

The proposal is to convert local timer drivers to be "standalone" (not relying on the local timer infrastructure) and to use a CPU notifier to have the timer brought up or down on non-boot CPUs.

The SMP support code can then be simplified to only manage the boadcast timer, which is always installed, and leave the generic kernel code to pick the highest priority timer. CONFIG_LOCAL_TIMERS disappears in the process.

Tested on EB11MP, OMAP4 and Tegra. Based on next-20111222.

Quoted 1 line

From v1:

- Various bug fixes
- DT support for smp_twd
- Added support for highbank and imx6q

Marc Zyngier (15):
ARM: local timers: allow smp_twd to be used standalone
ARM: smp_twd: add device tree support
ARM: local timers: switch realview to standalone smp_twd
ARM: local timers: switch vexpress to standalone smp_twd
ARM: local timers: remove localtimer.c from plat-versatile
ARM: local timers: switch tegra to standalone smp_twd
ARM: local timers: switch omap4 to standalone smp_twd
ARM: local timers: switch shmobile to standalone smp_twd
ARM: local timers: switch ux500 to standalone smp_twd
ARM: local timers: switch highbank to standalone smp_twd
ARM: local timers: switch imx6q to standalone smp_twd
ARM: smp_twd: remove support for non-standalone version
ARM: local timers: make MCT timer standalone
ARM: local timers: make MSM timers standalone
ARM: local timers: Remove CONFIG_LOCAL_TIMERS support

 Documentation/devicetree/bindings/arm/twd.txt |   29 +++++
 arch/arm/Kconfig                              |   15 +--
 arch/arm/include/asm/localtimer.h             |   57 ---------
 arch/arm/include/asm/smp_twd.h                |   19 +++-
 arch/arm/kernel/smp.c                         |   54 ++-------
 arch/arm/kernel/smp_twd.c                     |  155 +++++++++++++++++++------
 arch/arm/mach-exynos/mct.c                    |   85 ++++++++++----
 arch/arm/mach-highbank/Makefile               |    1 -
 arch/arm/mach-highbank/highbank.c             |   13 ++
 arch/arm/mach-highbank/localtimer.c           |   40 -------
 arch/arm/mach-imx/Makefile                    |    1 -
 arch/arm/mach-imx/localtimer.c                |   35 ------
 arch/arm/mach-imx/mach-imx6q.c                |   12 ++
 arch/arm/mach-msm/timer.c                     |   92 +++++++++++----
 arch/arm/mach-omap2/Kconfig                   |    2 +-
 arch/arm/mach-omap2/Makefile                  |    1 -
 arch/arm/mach-omap2/timer-mpu.c               |   39 ------
 arch/arm/mach-omap2/timer.c                   |   38 +++++-
 arch/arm/mach-realview/Kconfig                |    3 +
 arch/arm/mach-realview/realview_eb.c          |   33 +++++-
 arch/arm/mach-realview/realview_pb11mp.c      |   31 +++++-
 arch/arm/mach-realview/realview_pbx.c         |   30 +++++-
 arch/arm/mach-shmobile/Kconfig                |    1 +
 arch/arm/mach-shmobile/Makefile               |    1 -
 arch/arm/mach-shmobile/include/mach/common.h  |    3 +
 arch/arm/mach-shmobile/localtimer.c           |   26 ----
 arch/arm/mach-shmobile/smp-sh73a0.c           |   32 +++++-
 arch/arm/mach-shmobile/timer.c                |   10 ++
 arch/arm/mach-tegra/Kconfig                   |    1 +
 arch/arm/mach-tegra/Makefile                  |    2 +-
 arch/arm/mach-tegra/localtimer.c              |   26 ----
 arch/arm/mach-tegra/timer.c                   |   34 +++++-
 arch/arm/mach-ux500/Kconfig                   |    1 +
 arch/arm/mach-ux500/Makefile                  |    1 -
 arch/arm/mach-ux500/localtimer.c              |   29 -----
 arch/arm/mach-ux500/timer.c                   |   41 ++++++-
 arch/arm/mach-vexpress/Kconfig                |    1 +
 arch/arm/mach-vexpress/ct-ca9x4.c             |   29 ++++-
 arch/arm/plat-versatile/Makefile              |    1 -
 arch/arm/plat-versatile/localtimer.c          |   27 -----
 40 files changed, 591 insertions(+), 460 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/twd.txt
 delete mode 100644 arch/arm/include/asm/localtimer.h
 delete mode 100644 arch/arm/mach-highbank/localtimer.c
 delete mode 100644 arch/arm/mach-imx/localtimer.c
 delete mode 100644 arch/arm/mach-omap2/timer-mpu.c
 delete mode 100644 arch/arm/mach-shmobile/localtimer.c
 delete mode 100644 arch/arm/mach-tegra/localtimer.c
 delete mode 100644 arch/arm/mach-ux500/localtimer.c
 delete mode 100644 arch/arm/plat-versatile/localtimer.c
Signature · 1 line
1.7.7.1
#1 lore raw

PATCH v2 1/15 ARM: local timers: allow smp_twd to be used standalone

Allow smp_twd to be built in a "standalone" version, without relying on the CONFIG_LOCAL_TIMER infrastructure. It mainly relies on a CPU notifier block to stop or start the timer on the right CPU.

The CONFIG_ARM_SMP_TWD option selects the new behaviour.

---
 arch/arm/Kconfig               |    6 +++-
 arch/arm/include/asm/smp_twd.h |    9 +++++
 arch/arm/kernel/smp_twd.c      |   79 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 92 insertions(+), 2 deletions(-)
arch/arm/Kconfig +5 -1
index 6f3e186..c37410a 100644
@@ -1522,6 +1522,10 @@ config HAVE_ARM_TWD
 	help
 	  This options enables support for the ARM timer and watchdog unit
 
+config ARM_SMP_TWD
+	bool
+	select HAVE_ARM_TWD if SMP
+
 choice
 	prompt "Memory split"
 	default VMSPLIT_3G
@@ -1560,7 +1564,7 @@ config HOTPLUG_CPU
 
 config LOCAL_TIMERS
 	bool "Use local timer interrupts"
-	depends on SMP
+	depends on SMP && !ARM_SMP_TWD
 	default y
 	select HAVE_ARM_TWD if (!ARCH_MSM_SCORPIONMP && !EXYNOS4_MCT)
 	help
arch/arm/include/asm/smp_twd.h +9 -0
index ef9ffba9..934f1bc 100644
@@ -19,10 +19,19 @@
 #define TWD_TIMER_CONTROL_IT_ENABLE	(1 << 2)
 
 struct clock_event_device;
+struct resource;
 
 extern void __iomem *twd_base;
 
 void twd_timer_setup(struct clock_event_device *);
 void twd_timer_stop(struct clock_event_device *);
+#ifdef CONFIG_HAVE_ARM_TWD
+int twd_timer_register(struct resource *res, int res_nr);
+#else
+static inline int twd_timer_register(struct resource *res, int res_nr)
+{
+	return 0;
+}
+#endif
 
 #endif
arch/arm/kernel/smp_twd.c +78 -1

99 lines not on this page · raw message

Signature · 1 line
1.7.7.1
#2 lore raw

PATCH v2 1/15 ARM: local timers: allow smp_twd to be used standalone

arch/arm/kernel/smp_twd.c void __cpuinit twd_timer_setup(struct clock_event_device *clk) · line 260

Quoted 11 lines · Marc Zyngier
arch/arm/kernel/smp_twd.c +11 -0
+	twd_clock_event	= alloc_percpu(struct clock_event_device);
+	if (!twd_base || !twd_clock_event) {
+		iounmap(twd_base);
+		twd_base = NULL;
+		free_percpu(twd_clock_event);
+		return -ENOMEM;
+	}
+
+	/* Immediately configure the timer on the boot CPU */
+	clk = per_cpu_ptr(twd_clock_event, smp_processor_id());
+	twd_setup(clk);

This is insufficient. A proper local timer has this:

	evt->cpumask = cpumask_of(cpu);
	evt->broadcast = smp_timer_broadcast;

as well as all the rest of the normal clock event stuff. The broadcast callback is used when the timer core wants to broadcast the timer tick to other CPUs - see tick_do_broadcast() in kernel/time/tick-broadcast.c. The selection of which clock event device to use is rather 'optimized' for current conditions, and registering local timers without this is likely to oops the kernel at some point.

I don't think you can register separate clock event devices for use as the broadcast device vs the local timer device.

So, either you _have_ to use the SMP supplied version, or we make the broadcast function public and have everyone conditionally set that up, or something else... either way this is getting exceedingly messy.

That's why I believe it's far simpler to just say no to using twd as a global timer, and just keep it for SMP local timer purposes.

#3 lore raw

PATCH v2 2/15 ARM: smp_twd: add device tree support

In reply to Marc Zyngier

Add bindings to support DT discovery of the ARM Timer Watchdog (aka TWD). Only the timer side is converted by this patch.

---
 Documentation/devicetree/bindings/arm/twd.txt |   29 +++++++++++
 arch/arm/include/asm/smp_twd.h                |    7 +++
 arch/arm/kernel/smp_twd.c                     |   67 +++++++++++++++++++-----
 3 files changed, 89 insertions(+), 14 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/twd.txt
Documentation/devicetree/bindings/arm/twd.txt new file +29 -0
new file mode 100644
index 0000000..a9d5587
@@ -0,0 +1,29 @@
+* ARM Timer Watchdog
+
+ARM 11MP, Cortex-A5 and Cortex-A9 are often associated with a per-core
+Timer-Watchdog (aka TWD), which provides both a per-cpu local timer
+and watchdog.
+
+The TWD is usually attached to a GIC to deliver its two per-processor
+interrupts.
+
+Main node required properties:
+
+- compatible : Should be one of:
+	"arm,cortex-a9-twd"
+	"arm,cortex-a5-twd"
+	"arm,arm11mp-twd"
+	"arm,smp-twd"
+
+- interrupts : Two interrupts to each core, the first one for the
+  timer, the second one for the watchdog.
+
+- reg : Specify the base address and the size of the TWD.
+
+Example:
+
+	twd at 2c000600 {
+		compatible = "arm,arm11mp-twd", "arm,smp-twd";
+		reg = <0x2c000600 0x100>;
+		interrupts = <1 13 0xf01 1 14 0xf01>;
+	};
arch/arm/include/asm/smp_twd.h +7 -0
index 934f1bc..09c3b71 100644
@@ -20,6 +20,7 @@
 
 struct clock_event_device;
 struct resource;
+struct of_device_id;
 
 extern void __iomem *twd_base;
 
@@ -27,11 +28,17 @@ void twd_timer_setup(struct clock_event_device *);
 void twd_timer_stop(struct clock_event_device *);
 #ifdef CONFIG_HAVE_ARM_TWD
 int twd_timer_register(struct resource *res, int res_nr);
+int twd_timer_of_init(const struct of_device_id *twd_of_match);
 #else
 static inline int twd_timer_register(struct resource *res, int res_nr)
 {
 	return 0;
 }
+
+static inline int twd_timer_of_init(const struct of_device_id *twd_of_match)
+{
+	return 0;
+}
 #endif
 
 #endif
arch/arm/kernel/smp_twd.c +53 -14

92 lines not on this page · raw message

Signature · 1 line
1.7.7.1
#4 lore raw

PATCH v2 3/15 ARM: local timers: switch realview to standalone smp_twd

In reply to Marc Zyngier

Convert the SMP RealView platforms to the standalone version of smp_twd.c. Since the timer calibration code requires another timer to be up and running, the actual initialisation is left to the late_timer_init hook.

Tested on EB-11MP.

---
 arch/arm/mach-realview/Kconfig           |    3 ++
 arch/arm/mach-realview/realview_eb.c     |   33 ++++++++++++++++++++++++++---
 arch/arm/mach-realview/realview_pb11mp.c |   31 ++++++++++++++++++++++++---
 arch/arm/mach-realview/realview_pbx.c    |   30 ++++++++++++++++++++++++--
 4 files changed, 86 insertions(+), 11 deletions(-)
arch/arm/mach-realview/Kconfig +3 -0
index dba6d0c..135a7ea 100644
@@ -4,6 +4,7 @@ menu "RealView platform type"
 config MACH_REALVIEW_EB
 	bool "Support RealView(R) Emulation Baseboard"
 	select ARM_GIC
+	select ARM_SMP_TWD if SMP
 	help
 	  Include support for the ARM(R) RealView(R) Emulation Baseboard
 	  platform.
@@ -40,6 +41,7 @@ config MACH_REALVIEW_PB11MP
 	select ARM_GIC
 	select HAVE_PATA_PLATFORM
 	select ARCH_HAS_BARRIERS if SMP
+	select ARM_SMP_TWD if SMP
 	help
 	  Include support for the ARM(R) RealView(R) Platform Baseboard for
 	  the ARM11MPCore.  This platform has an on-board ARM11MPCore and has
@@ -80,6 +82,7 @@ config MACH_REALVIEW_PBX
 	select HAVE_PATA_PLATFORM
 	select ARCH_SPARSEMEM_ENABLE if CPU_V7 && !REALVIEW_HIGH_PHYS_OFFSET
 	select ZONE_DMA if SPARSEMEM
+	select ARM_SMP_TWD if SMP
 	help
 	  Include support for the ARM(R) RealView(R) Platform Baseboard
 	  Explore.
arch/arm/mach-realview/realview_eb.c +29 -4
index f92a920..75cd6ef 100644
@@ -36,7 +36,7 @@
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
-#include <asm/localtimer.h>
+#include <asm/smp_twd.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -391,6 +391,33 @@ static void realview_eb11mp_fixup(void)
 	realview_eb_isp1761_resources[1].end	= IRQ_EB11MP_USB;
 }
 
+#ifdef CONFIG_ARM_SMP_TWD
+static struct resource twd_resources[] __initdata = {
+	{
+		.start	= REALVIEW_EB11MP_TWD_BASE,
+		.end	= REALVIEW_EB11MP_TWD_BASE + 0xff,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_LOCALTIMER,
+		.end	= IRQ_LOCALTIMER,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static void __init realview_eb_twd_init(void)
+{
+	if (core_tile_eb11mp() || core_tile_a9mp()) {
+		int err = twd_timer_register(twd_resources,
+					     ARRAY_SIZE(twd_resources));
+		if (err)
+			pr_err("twd_timer_register failed %d\n", err);
+	}
+}
+#else
+#define realview_eb_twd_init	NULL
+#endif
+
 static void __init realview_eb_timer_init(void)
 {
 	unsigned int timer_irq;
@@ -401,9 +428,7 @@ static void __init realview_eb_timer_init(void)
 	timer3_va_base = __io_address(REALVIEW_EB_TIMER2_3_BASE) + 0x20;
 
 	if (core_tile_eb11mp() || core_tile_a9mp()) {
-#ifdef CONFIG_LOCAL_TIMERS
-		twd_base = __io_address(REALVIEW_EB11MP_TWD_BASE);
-#endif
+		late_time_init = realview_eb_twd_init;
 		timer_irq = IRQ_EB11MP_TIMER0_1;
 	} else
 		timer_irq = IRQ_EB_TIMER0_1;
arch/arm/mach-realview/realview_pb11mp.c +27 -4
index f035fda..b164772 100644
@@ -36,7 +36,7 @@
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
-#include <asm/localtimer.h>
+#include <asm/smp_twd.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
@@ -298,6 +298,31 @@ static void __init gic_init_irq(void)
 	gic_cascade_irq(1, IRQ_TC11MP_PB_IRQ1);
 }
 
+#ifdef CONFIG_ARM_SMP_TWD
+static struct resource realview_pb11mp_twd_resources[] __initdata = {
+	{
+		.start	= REALVIEW_TC11MP_TWD_BASE,
+		.end	= REALVIEW_TC11MP_TWD_BASE + 0x10,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_LOCALTIMER,
+		.end	= IRQ_LOCALTIMER,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static void __init realview_pb11mp_twd_init(void)
+{
+	int err = twd_timer_register(realview_pb11mp_twd_resources,
+				     ARRAY_SIZE(realview_pb11mp_twd_resources));
+	if (err)
+		pr_err("twd_timer_register failed %d\n", err);
+}
+#else
+#define realview_pb11mp_twd_init	NULL
+#endif
+
 static void __init realview_pb11mp_timer_init(void)
 {
 	timer0_va_base = __io_address(REALVIEW_PB11MP_TIMER0_1_BASE);
@@ -305,10 +330,8 @@ static void __init realview_pb11mp_timer_init(void)
 	timer2_va_base = __io_address(REALVIEW_PB11MP_TIMER2_3_BASE);
 	timer3_va_base = __io_address(REALVIEW_PB11MP_TIMER2_3_BASE) + 0x20;
 
-#ifdef CONFIG_LOCAL_TIMERS
-	twd_base = __io_address(REALVIEW_TC11MP_TWD_BASE);
-#endif
 	realview_timer_init(IRQ_TC11MP_TIMER0_1);
+	late_time_init = realview_pb11mp_twd_init;
 }
 
 static struct sys_timer realview_pb11mp_timer = {
arch/arm/mach-realview/realview_pbx.c +27 -3
index 0194b3e..d833935 100644
@@ -301,6 +301,31 @@ static void __init gic_init_irq(void)
 	}
 }
 
+#ifdef CONFIG_ARM_SMP_TWD
+static struct resource realview_pbx_twd_resources[] __initdata = {
+	{
+		.start	= REALVIEW_PBX_TILE_TWD_BASE,
+		.end	= REALVIEW_PBX_TILE_TWD_BASE + 0x10,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_LOCALTIMER,
+		.end	= IRQ_LOCALTIMER,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static void __init realview_pbx_twd_init(void)
+{
+	int err = twd_timer_register(realview_pbx_twd_resources,
+				     ARRAY_SIZE(realview_pbx_twd_resources));
+	if (err)
+		pr_err("twd_timer_register failed %d\n", err);
+}
+#else
+#define realview_pbx_twd_init	NULL
+#endif
+
 static void __init realview_pbx_timer_init(void)
 {
 	timer0_va_base = __io_address(REALVIEW_PBX_TIMER0_1_BASE);
@@ -308,10 +333,9 @@ static void __init realview_pbx_timer_init(void)
 	timer2_va_base = __io_address(REALVIEW_PBX_TIMER2_3_BASE);
 	timer3_va_base = __io_address(REALVIEW_PBX_TIMER2_3_BASE) + 0x20;
 
-#ifdef CONFIG_LOCAL_TIMERS
 	if (core_tile_pbx11mp() || core_tile_pbxa9mp())
-		twd_base = __io_address(REALVIEW_PBX_TILE_TWD_BASE);
-#endif
+		late_time_init = realview_pbx_twd_init;
+
 	realview_timer_init(IRQ_PBX_TIMER0_1);
 }
 
Signature · 1 line
1.7.7.1
#5 lore raw

PATCH v2 4/15 ARM: local timers: switch vexpress to standalone smp_twd

In reply to Marc Zyngier

Convert the Versatile Express platform to the standalone version of smp_twd.c. Since the timer calibration code requires another timer to be up and running, the actual initialisation is left to the late_timer_init hook.

---
 arch/arm/mach-vexpress/Kconfig    |    1 +
 arch/arm/mach-vexpress/ct-ca9x4.c |   29 ++++++++++++++++++++++++++---
 2 files changed, 27 insertions(+), 3 deletions(-)
arch/arm/mach-vexpress/Kconfig +1 -0
index 9311484..13f1606 100644
@@ -5,6 +5,7 @@ config ARCH_VEXPRESS_CA9X4
 	bool "Versatile Express Cortex-A9x4 tile"
 	select CPU_V7
 	select ARM_GIC
+	select ARM_SMP_TWD
 	select ARM_ERRATA_720789
 	select ARM_ERRATA_751472
 	select ARM_ERRATA_753970
arch/arm/mach-vexpress/ct-ca9x4.c +26 -3
index 2b1e836..9ffa7e9 100644
@@ -53,9 +53,6 @@ static struct map_desc ct_ca9x4_io_desc[] __initdata = {
 
 static void __init ct_ca9x4_map_io(void)
 {
-#ifdef CONFIG_LOCAL_TIMERS
-	twd_base = MMIO_P2V(A9_MPCORE_TWD);
-#endif
 	iotable_init(ct_ca9x4_io_desc, ARRAY_SIZE(ct_ca9x4_io_desc));
 }
 
@@ -191,9 +188,35 @@ static struct platform_device pmu_device = {
 	.resource	= pmu_resources,
 };
 
+#ifdef CONFIG_ARM_SMP_TWD
+static struct resource ca9x4_twd_resources[] __initdata = {
+	{
+		.start	= A9_MPCORE_TWD,
+		.end	= A9_MPCORE_TWD + 0x10,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_LOCALTIMER,
+		.end	= IRQ_LOCALTIMER,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static void __init ca9x4_twd_init(void)
+{
+	int err = twd_timer_register(ca9x4_twd_resources,
+				     ARRAY_SIZE(ca9x4_twd_resources));
+	if (err)
+		pr_err("twd_timer_register failed %d\n", err);
+}
+#else
+#define ca9x4_twd_init	NULL
+#endif
+
 static void __init ct_ca9x4_init_early(void)
 {
 	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+	late_time_init = ca9x4_twd_init;
 }
 
 static void __init ct_ca9x4_init(void)
Signature · 1 line
1.7.7.1
#6 lore raw

PATCH v2 5/15 ARM: local timers: remove localtimer.c from plat-versatile

In reply to Marc Zyngier

As the localtimer infrastructure is not use anymore by any of the Versatile platforms, remove localtimer.c.

---
 arch/arm/plat-versatile/Makefile     |    1 -
 arch/arm/plat-versatile/localtimer.c |   27 ---------------------------
 2 files changed, 0 insertions(+), 28 deletions(-)
 delete mode 100644 arch/arm/plat-versatile/localtimer.c
arch/arm/plat-versatile/Makefile +0 -1
index 69714db..a5cb194 100644
@@ -1,5 +1,4 @@
 obj-y	:= clock.o
-obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
 obj-$(CONFIG_PLAT_VERSATILE_CLCD) += clcd.o
 obj-$(CONFIG_PLAT_VERSATILE_FPGA_IRQ) += fpga-irq.o
 obj-$(CONFIG_PLAT_VERSATILE_LEDS) += leds.o
arch/arm/plat-versatile/localtimer.c deleted +0 -27
deleted file mode 100644
index 0fb3961..0000000
@@ -1,27 +0,0 @@
-/*
- *  linux/arch/arm/plat-versatile/localtimer.c
- *
- *  Copyright (C) 2002 ARM Ltd.
- *  All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/clockchips.h>
-
-#include <asm/smp_twd.h>
-#include <asm/localtimer.h>
-#include <mach/irqs.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-	evt->irq = IRQ_LOCALTIMER;
-	twd_timer_setup(evt);
-	return 0;
-}
Signature · 1 line
1.7.7.1
#7 lore raw

PATCH v2 6/15 ARM: local timers: switch tegra to standalone smp_twd

In reply to Marc Zyngier

Convert the Tegra-2 platforms to the standalone version of smp_twd.c. Since the timer calibration code requires another timer to be up and running, the actual initialisation is left to the late_timer_init hook.

Tested on Harmony.

Cc Colin Cross <[email protected]>
Cc Erik Gilling <[email protected]>
Cc Olof Johansson <[email protected]>
Cc Stephen Warren <[email protected]>
---
 arch/arm/mach-tegra/Kconfig      |    1 +
 arch/arm/mach-tegra/Makefile     |    2 +-
 arch/arm/mach-tegra/localtimer.c |   26 --------------------------
 arch/arm/mach-tegra/timer.c      |   34 +++++++++++++++++++++++++++++-----
 4 files changed, 31 insertions(+), 32 deletions(-)
 delete mode 100644 arch/arm/mach-tegra/localtimer.c
arch/arm/mach-tegra/Kconfig +1 -0
index 373652d..f93aa6aa 100644
@@ -6,6 +6,7 @@ config ARCH_TEGRA_2x_SOC
 	bool "Enable support for Tegra20 family"
 	select CPU_V7
 	select ARM_GIC
+	select ARM_SMP_TWD
 	select ARCH_REQUIRE_GPIOLIB
 	select USB_ARCH_HAS_EHCI if USB_SUPPORT
 	select USB_ULPI if USB_SUPPORT
arch/arm/mach-tegra/Makefile +1 -1
index e120ff5..f7d0443 100644
@@ -13,7 +13,7 @@ obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= tegra2_emc.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= pinmux-tegra20-tables.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= pinmux-tegra30-tables.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= board-dt-tegra30.o
-obj-$(CONFIG_SMP)                       += platsmp.o localtimer.o headsmp.o
+obj-$(CONFIG_SMP)                       += platsmp.o headsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)               += hotplug.o
 obj-$(CONFIG_TEGRA_SYSTEM_DMA)		+= dma.o
 obj-$(CONFIG_CPU_FREQ)                  += cpu-tegra.o
arch/arm/mach-tegra/localtimer.c deleted +0 -26
deleted file mode 100644
index e91d681..0000000
@@ -1,26 +0,0 @@
-/*
- *  arch/arm/mach-tegra/localtimer.c
- *
- *  Copyright (C) 2002 ARM Ltd.
- *  All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/clockchips.h>
-#include <asm/irq.h>
-#include <asm/smp_twd.h>
-#include <asm/localtimer.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-	evt->irq = IRQ_LOCALTIMER;
-	twd_timer_setup(evt);
-	return 0;
-}
arch/arm/mach-tegra/timer.c +29 -5
index 6366654..0c537b9 100644
@@ -27,9 +27,10 @@
 #include <linux/clocksource.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/ioport.h>
 
 #include <asm/mach/time.h>
-#include <asm/localtimer.h>
+#include <asm/smp_twd.h>
 #include <asm/sched_clock.h>
 
 #include <mach/iomap.h>
@@ -179,6 +180,31 @@ static struct irqaction tegra_timer_irq = {
 	.irq		= INT_TMR3,
 };
 
+#ifdef CONFIG_ARM_SMP_TWD
+static struct resource tegra_twd_resources[] __initdata = {
+	{
+		.start	= TEGRA_ARM_PERIF_BASE + 0x600,
+		.end	= TEGRA_ARM_PERIF_BASE + 0x610,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_LOCALTIMER,
+		.end	= IRQ_LOCALTIMER,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static void __init tegra_twd_init(void)
+{
+	int err = twd_timer_register(tegra_twd_resources,
+				     ARRAY_SIZE(tegra_twd_resources));
+	if (err)
+		pr_err("twd_timer_register failed %d\n", err);
+}
+#else
+#define tegra_twd_init	NULL
+#endif
+
 static void __init tegra_init_timer(void)
 {
 	struct clk *clk;
@@ -205,10 +231,6 @@ static void __init tegra_init_timer(void)
 	else
 		clk_enable(clk);
 
-#ifdef CONFIG_HAVE_ARM_TWD
-	twd_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x600);
-#endif
-
 	switch (rate) {
 	case 12000000:
 		timer_writel(0x000b, TIMERUS_USEC_CFG);
@@ -249,6 +271,8 @@ static void __init tegra_init_timer(void)
 	tegra_clockevent.cpumask = cpu_all_mask;
 	tegra_clockevent.irq = tegra_timer_irq.irq;
 	clockevents_register_device(&tegra_clockevent);
+
+	late_time_init = tegra_twd_init;
 }
 
 struct sys_timer tegra_timer = {
Signature · 1 line
1.7.7.1
#8 lore raw

PATCH v2 6/15 ARM: local timers: switch tegra to standalone smp_twd

Quoted 5 lines · Marc Zyngier

Convert the Tegra-2 platforms to the standalone version of smp_twd.c. Since the timer calibration code requires another timer to be up and running, the actual initialisation is left to the late_timer_init hook.

Quoted 7 lines

Tested on Harmony.

Cc Colin Cross <[email protected]>
Cc Erik Gilling <[email protected]>
Cc Olof Johansson <[email protected]>
Cc Stephen Warren <[email protected]>
#9 lore raw

PATCH v2 7/15 ARM: local timers: switch omap4 to standalone smp_twd

In reply to Marc Zyngier

Convert the OMAP4 platforms to the standalone version of smp_twd.c. Since the timer calibration code requires another timer to be up and running, the actual initialisation is left to the late_timer_init hook.

Tested on a Pandaboard.

---
 arch/arm/mach-omap2/Kconfig     |    2 +-
 arch/arm/mach-omap2/Makefile    |    1 -
 arch/arm/mach-omap2/timer-mpu.c |   39 ---------------------------------------
 arch/arm/mach-omap2/timer.c     |   38 +++++++++++++++++++++++++++++++++-----
 4 files changed, 34 insertions(+), 46 deletions(-)
 delete mode 100644 arch/arm/mach-omap2/timer-mpu.c
arch/arm/mach-omap2/Kconfig +1 -1
index cb760ac..ab0c972 100644
@@ -45,7 +45,7 @@ config ARCH_OMAP4
 	depends on ARCH_OMAP2PLUS
 	select CPU_V7
 	select ARM_GIC
-	select LOCAL_TIMERS if SMP
+	select ARM_SMP_TWD
 	select PL310_ERRATA_588369
 	select PL310_ERRATA_727915
 	select ARM_ERRATA_720789
arch/arm/mach-omap2/Makefile +0 -1
index fc9b238..27ea7c2 100644
@@ -23,7 +23,6 @@ obj-$(CONFIG_TWL4030_CORE) += omap_twl.o
 
 # SMP support ONLY available for OMAP4
 obj-$(CONFIG_SMP)			+= omap-smp.o omap-headsmp.o
-obj-$(CONFIG_LOCAL_TIMERS)		+= timer-mpu.o
 obj-$(CONFIG_HOTPLUG_CPU)		+= omap-hotplug.o
 obj-$(CONFIG_ARCH_OMAP4)		+= omap4-common.o omap-wakeupgen.o \
 					   sleep44xx.o
arch/arm/mach-omap2/timer-mpu.c deleted +0 -39
deleted file mode 100644
index 31c0ac4..0000000
@@ -1,39 +0,0 @@
-/*
- * The MPU local timer source file. In OMAP4, both cortex-a9 cores have
- * own timer in it's MPU domain. These timers will be driving the
- * linux kernel SMP tick framework when active. These timers are not
- * part of the wake up domain.
- *
- * Copyright (C) 2009 Texas Instruments, Inc.
- *
- * Author:
- *      Santosh Shilimkar <[email protected]>
- *
- * This file is based on arm realview smp platform file.
- * Copyright (C) 2002 ARM Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/clockchips.h>
-#include <asm/irq.h>
-#include <asm/smp_twd.h>
-#include <asm/localtimer.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-	/* Local timers are not supprted on OMAP4430 ES1.0 */
-	if (omap_rev() == OMAP4430_REV_ES1_0)
-		return -ENXIO;
-
-	evt->irq = OMAP44XX_IRQ_LOCALTIMER;
-	twd_timer_setup(evt);
-	return 0;
-}
-
arch/arm/mach-omap2/timer.c +33 -5
index 9edcd52..a69e686 100644
@@ -39,7 +39,7 @@
 
 #include <asm/mach/time.h>
 #include <plat/dmtimer.h>
-#include <asm/localtimer.h>
+#include <asm/smp_twd.h>
 #include <asm/sched_clock.h>
 #include "common.h"
 #include <plat/omap_hwmod.h>
@@ -335,15 +335,43 @@ OMAP_SYS_TIMER_INIT(3_secure, OMAP3_SECURE_TIMER, OMAP3_CLKEV_SOURCE,
 OMAP_SYS_TIMER(3_secure)
 #endif
 
+#ifdef CONFIG_ARM_SMP_TWD
+static struct resource omap4_twd_resources[] __initdata = {
+	{
+		.start	= OMAP44XX_LOCAL_TWD_BASE,
+		.end	= OMAP44XX_LOCAL_TWD_BASE + 0x10,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= OMAP44XX_IRQ_LOCALTIMER,
+		.end	= OMAP44XX_IRQ_LOCALTIMER,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static void __init omap4_twd_init(void)
+{
+	int err;
+
+	/* Local timers are not supprted on OMAP4430 ES1.0 */
+	if (omap_rev() == OMAP4430_REV_ES1_0)
+		return;
+
+	err = twd_timer_register(omap4_twd_resources,
+				 ARRAY_SIZE(omap4_twd_resources));
+	if (err)
+		pr_err("twd_timer_register failed %d\n", err);
+}
+#else
+#define omap4_twd_init	NULL
+#endif
+
 #ifdef CONFIG_ARCH_OMAP4
 static void __init omap4_timer_init(void)
 {
-#ifdef CONFIG_LOCAL_TIMERS
-	twd_base = ioremap(OMAP44XX_LOCAL_TWD_BASE, SZ_256);
-	BUG_ON(!twd_base);
-#endif
 	omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE);
 	omap2_gp_clocksource_init(2, OMAP4_MPU_SOURCE);
+	late_time_init = omap4_twd_init;
 }
 OMAP_SYS_TIMER(4)
 #endif
Signature · 1 line
1.7.7.1
#10 lore raw

PATCH v2 7/15 ARM: local timers: switch omap4 to standalone smp_twd

Marc,

Quoted 9 lines · Marc Zyngier

Convert the OMAP4 platforms to the standalone version of smp_twd.c. Since the timer calibration code requires another timer to be up and running, the actual initialisation is left to the late_timer_init hook.

Tested on a Pandaboard.

IIRC, have reviewed this earlier. Looking at the patch the changes are almost same. So for OMAP changes

#11 lore raw

PATCH v2 8/15 ARM: local timers: switch shmobile to standalone smp_twd

In reply to Marc Zyngier

Convert the SMP shmobile platforms to the standalone version of smp_twd.c. As shmobile is already using the late_time_init hook, a private hook is added to initialise the TWD driver once the platform timer is up and running.

Cc Paul Mundt <[email protected]>
Cc Magnus Damm <[email protected]>
---
 arch/arm/mach-shmobile/Kconfig               |    1 +
 arch/arm/mach-shmobile/Makefile              |    1 -
 arch/arm/mach-shmobile/include/mach/common.h |    3 ++
 arch/arm/mach-shmobile/localtimer.c          |   26 ---------------------
 arch/arm/mach-shmobile/smp-sh73a0.c          |   32 +++++++++++++++++++++++--
 arch/arm/mach-shmobile/timer.c               |   10 ++++++++
 6 files changed, 43 insertions(+), 30 deletions(-)
 delete mode 100644 arch/arm/mach-shmobile/localtimer.c
arch/arm/mach-shmobile/Kconfig +1 -0
index 0828fab..a46db89 100644
@@ -23,6 +23,7 @@ config ARCH_SH7372
 config ARCH_SH73A0
 	bool "SH-Mobile AG5 (R8A73A00)"
 	select CPU_V7
+	select ARM_SMP_TWD
 	select SH_CLK_CPG
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_GIC
arch/arm/mach-shmobile/Makefile +0 -1
index 5ca1f9d..85c5166 100644
@@ -14,7 +14,6 @@ obj-$(CONFIG_ARCH_SH73A0)	+= setup-sh73a0.o clock-sh73a0.o intc-sh73a0.o
 # SMP objects
 smp-y				:= platsmp.o headsmp.o
 smp-$(CONFIG_HOTPLUG_CPU)	+= hotplug.o
-smp-$(CONFIG_LOCAL_TIMERS)	+= localtimer.o
 smp-$(CONFIG_ARCH_SH73A0)	+= smp-sh73a0.o
 
 # Pinmux setup
arch/arm/mach-shmobile/include/mach/common.h +3 -0
index 4bf82c1..658c6ec 100644
@@ -52,4 +52,7 @@ extern void sh73a0_secondary_init(unsigned int cpu);
 extern int sh73a0_boot_secondary(unsigned int cpu);
 extern void sh73a0_smp_prepare_cpus(void);
 
+struct resource;
+extern void shmobile_local_timer_register(void (*)(void));
+
 #endif /* __ARCH_MACH_COMMON_H */
arch/arm/mach-shmobile/localtimer.c deleted +0 -26
deleted file mode 100644
index ad9ccc9..0000000
@@ -1,26 +0,0 @@
-/*
- * SMP support for R-Mobile / SH-Mobile - local timer portion
- *
- * Copyright (C) 2010  Magnus Damm
- *
- * Based on vexpress, Copyright (C) 2002 ARM Ltd, All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/clockchips.h>
-#include <asm/smp_twd.h>
-#include <asm/localtimer.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-	evt->irq = 29;
-	twd_timer_setup(evt);
-	return 0;
-}
arch/arm/mach-shmobile/smp-sh73a0.c +29 -3
index be1ade7..cb5f011 100644
@@ -22,6 +22,7 @@
 #include <linux/smp.h>
 #include <linux/spinlock.h>
 #include <linux/io.h>
+#include <linux/ioport.h>
 #include <mach/common.h>
 #include <asm/smp_scu.h>
 #include <asm/smp_twd.h>
@@ -41,6 +42,31 @@ static void __iomem *scu_base_addr(void)
 static DEFINE_SPINLOCK(scu_lock);
 static unsigned long tmp;
 
+#ifdef CONFIG_ARM_SMP_TWD
+static struct resource sh73a0_twd_resources[] __initdata = {
+	{
+		.start	= 0xf0000600,
+		.end	= 0xf0000600 + 0x10,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= 29,
+		.end	= 29,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static void __init sh73a0_twd_init(void)
+{
+	int err = twd_timer_register(sh73a0_twd_resources,
+				     ARRAY_SIZE(sh73a0_twd_resources));
+	if (err)
+		pr_err("twd_timer_register failed %d\n", err);
+}
+#else
+#define sh73a0_twd_init	NULL
+#endif
+
 static void modify_scu_cpu_psr(unsigned long set, unsigned long clr)
 {
 	void __iomem *scu_base = scu_base_addr();
@@ -59,9 +85,9 @@ unsigned int __init sh73a0_get_core_count(void)
 {
 	void __iomem *scu_base = scu_base_addr();
 
-#ifdef CONFIG_HAVE_ARM_TWD
-	/* twd_base needs to be initialized before percpu_timer_setup() */
-	twd_base = (void __iomem *)0xf0000600;
+
+#ifdef CONFIG_ARM_SMP_TWD
+	shmobile_local_timer_register(sh73a0_twd_init);
 #endif
 
 	return scu_get_core_count(scu_base);
arch/arm/mach-shmobile/timer.c +10 -0
index 895794b..fad385d 100644
@@ -19,8 +19,11 @@
  *
  */
 #include <linux/platform_device.h>
+#include <mach/common.h>
 #include <asm/mach/time.h>
 
+static void (*local_timer_hook)(void) __initdata;
+
 static void __init shmobile_late_time_init(void)
 {
 	/*
@@ -34,6 +37,8 @@ static void __init shmobile_late_time_init(void)
 	 */
 	early_platform_driver_register_all("earlytimer");
 	early_platform_driver_probe("earlytimer", 2, 0);
+	if (local_timer_hook)
+		local_timer_hook();
 }
 
 static void __init shmobile_timer_init(void)
@@ -41,6 +46,11 @@ static void __init shmobile_timer_init(void)
 	late_time_init = shmobile_late_time_init;
 }
 
+void __init shmobile_local_timer_register(void (*hook)(void))
+{
+	local_timer_hook = hook;
+}
+
 struct sys_timer shmobile_timer = {
 	.init		= shmobile_timer_init,
 };
Signature · 1 line
1.7.7.1
#12 lore raw

PATCH v2 9/15 ARM: local timers: switch ux500 to standalone smp_twd

In reply to Marc Zyngier

Convert the ux500 platforms to the standalone version of smp_twd.c. Since the timer calibration code requires another timer to be up and running, the actual initialisation is left to the late_timer_init hook.

---
 arch/arm/mach-ux500/Kconfig      |    1 +
 arch/arm/mach-ux500/Makefile     |    1 -
 arch/arm/mach-ux500/localtimer.c |   29 --------------------------
 arch/arm/mach-ux500/timer.c      |   41 +++++++++++++++++++++++++++++++------
 4 files changed, 35 insertions(+), 37 deletions(-)
 delete mode 100644 arch/arm/mach-ux500/localtimer.c
arch/arm/mach-ux500/Kconfig +1 -0
index a3e0c86..f69bd06 100644
@@ -4,6 +4,7 @@ config UX500_SOC_COMMON
 	bool
 	default y
 	select ARM_GIC
+	select ARM_SMP_TWD
 	select HAS_MTU
 	select ARM_ERRATA_753970
 	select ARM_ERRATA_754322
arch/arm/mach-ux500/Makefile +0 -1
index 6bd2f45..35b3894 100644
@@ -15,7 +15,6 @@ obj-$(CONFIG_MACH_U8500)	+= board-mop500.o board-mop500-sdi.o \
 obj-$(CONFIG_MACH_U5500)	+= board-u5500.o board-u5500-sdi.o
 obj-$(CONFIG_SMP)		+= platsmp.o headsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)	+= hotplug.o
-obj-$(CONFIG_LOCAL_TIMERS)	+= localtimer.o
 obj-$(CONFIG_U5500_MODEM_IRQ)	+= modem-irq-db5500.o
 obj-$(CONFIG_U5500_MBOX)	+= mbox-db5500.o
 
arch/arm/mach-ux500/localtimer.c deleted +0 -29
deleted file mode 100644
index 5ba1133..0000000
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2008-2009 ST-Ericsson
- * Srinidhi Kasagar <[email protected]>
- *
- * This file is heavily based on relaview platform, almost a copy.
- *
- * Copyright (C) 2002 ARM Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/clockchips.h>
-
-#include <asm/irq.h>
-#include <asm/smp_twd.h>
-#include <asm/localtimer.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-	evt->irq = IRQ_LOCALTIMER;
-	twd_timer_setup(evt);
-	return 0;
-}
arch/arm/mach-ux500/timer.c +34 -7

67 lines not on this page · raw message

Signature · 1 line
1.7.7.1
#13 lore raw

PATCH v2 10/15 ARM: local timers: switch highbank to standalone smp_twd

In reply to Marc Zyngier

Convert the highbank platform to the standalone version of smp_twd.c. Since the timer calibration code requires another timer to be up and running, the actual initialisation is left to the late_timer_init hook.

---
 arch/arm/mach-highbank/Makefile     |    1 -
 arch/arm/mach-highbank/highbank.c   |   13 +++++++++++
 arch/arm/mach-highbank/localtimer.c |   40 -----------------------------------
 3 files changed, 13 insertions(+), 41 deletions(-)
 delete mode 100644 arch/arm/mach-highbank/localtimer.c
arch/arm/mach-highbank/Makefile +0 -1
index 986958a..f8437dd 100644
@@ -1,6 +1,5 @@
 obj-y					:= clock.o highbank.o system.o
 obj-$(CONFIG_DEBUG_HIGHBANK_UART)	+= lluart.o
 obj-$(CONFIG_SMP)			+= platsmp.o
-obj-$(CONFIG_LOCAL_TIMERS)		+= localtimer.o
 obj-$(CONFIG_HOTPLUG_CPU)		+= hotplug.o
 obj-$(CONFIG_PM_SLEEP)			+= pm.o
arch/arm/mach-highbank/highbank.c +13 -0
index 804c4a5..6a60919 100644
@@ -27,6 +27,7 @@
 #include <asm/cacheflush.h>
 #include <asm/unified.h>
 #include <asm/smp_scu.h>
+#include <asm/smp_twd.h>
 #include <asm/hardware/arm_timer.h>
 #include <asm/hardware/timer-sp.h>
 #include <asm/hardware/gic.h>
@@ -93,6 +94,16 @@ static void __init highbank_init_irq(void)
 	l2x0_of_init(0, ~0UL);
 }
 
+const static struct of_device_id twd_match[] __initconst = {
+	{ .compatible = "arm,smp-twd", },
+	{}
+};
+
+static void __init highbank_twd_init(void)
+{
+	twd_timer_of_init(twd_match);
+}
+
 static void __init highbank_timer_init(void)
 {
 	int irq;
@@ -113,6 +124,8 @@ static void __init highbank_timer_init(void)
 
 	sp804_clocksource_init(timer_base + 0x20, "timer1");
 	sp804_clockevents_init(timer_base, irq, "timer0");
+
+	late_time_init = highbank_twd_init;
 }
 
 static struct sys_timer highbank_timer = {
arch/arm/mach-highbank/localtimer.c deleted +0 -40
deleted file mode 100644
index 5a00e79..0000000
@@ -1,40 +0,0 @@
-/*
- * Copyright 2010-2011 Calxeda, Inc.
- * Based on localtimer.c, Copyright (C) 2002 ARM Ltd.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-#include <linux/init.h>
-#include <linux/clockchips.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-
-#include <asm/smp_twd.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-	struct device_node *np;
-
-	np = of_find_compatible_node(NULL, NULL, "arm,smp-twd");
-	if (!twd_base) {
-		twd_base = of_iomap(np, 0);
-		WARN_ON(!twd_base);
-	}
-	evt->irq = irq_of_parse_and_map(np, 0);
-	twd_timer_setup(evt);
-	return 0;
-}
Signature · 1 line
1.7.7.1
#14 lore raw

PATCH v2 11/15 ARM: local timers: switch imx6q to standalone smp_twd

In reply to Marc Zyngier

Convert the imx6q platforms to the standalone version of smp_twd.c. Since the timer calibration code requires another timer to be up and running, the actual initialisation is left to the late_timer_init hook.

---
 arch/arm/mach-imx/Makefile     |    1 -
 arch/arm/mach-imx/localtimer.c |   35 -----------------------------------
 arch/arm/mach-imx/mach-imx6q.c |   12 ++++++++++++
 3 files changed, 12 insertions(+), 36 deletions(-)
 delete mode 100644 arch/arm/mach-imx/localtimer.c
arch/arm/mach-imx/Makefile +0 -1
index 88a3966..94cbed6 100644
@@ -71,7 +71,6 @@ obj-$(CONFIG_CPU_V7) += head-v7.o
 AFLAGS_head-v7.o :=-Wa,-march=armv7-a
 obj-$(CONFIG_SMP) += platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
-obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
 obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o pm-imx6q.o
 
 # i.MX5 based machines
arch/arm/mach-imx/localtimer.c deleted +0 -35
deleted file mode 100644
index 3a16351..0000000
@@ -1,35 +0,0 @@
-/*
- * Copyright 2011 Freescale Semiconductor, Inc.
- * Copyright 2011 Linaro Ltd.
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/init.h>
-#include <linux/clockchips.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <asm/smp_twd.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-	struct device_node *np;
-
-	np = of_find_compatible_node(NULL, NULL, "arm,smp-twd");
-	if (!twd_base) {
-		twd_base = of_iomap(np, 0);
-		WARN_ON(!twd_base);
-	}
-	evt->irq = irq_of_parse_and_map(np, 0);
-	twd_timer_setup(evt);
-
-	return 0;
-}
arch/arm/mach-imx/mach-imx6q.c +12 -0
index c257281..85031b8 100644
@@ -21,6 +21,7 @@
 #include <linux/of_platform.h>
 #include <linux/phy.h>
 #include <linux/micrel_phy.h>
+#include <asm/smp_twd.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/hardware/gic.h>
 #include <asm/mach/arch.h>
@@ -116,9 +117,20 @@ static void __init imx6q_init_irq(void)
 	of_irq_init(imx6q_irq_match);
 }
 
+const static struct of_device_id imx6q_twd_match[] __initconst = {
+	{ .compatible = "arm,smp-twd", },
+	{}
+};
+
+static void __init imx6q_twd_init(void)
+{
+	twd_timer_of_init(imx6q_twd_match);
+}
+
 static void __init imx6q_timer_init(void)
 {
 	mx6q_clocks_init();
+	late_time_init = imx6q_twd_init;
 }
 
 static struct sys_timer imx6q_timer = {
Signature · 1 line
1.7.7.1
#15 lore raw

PATCH v2 11/15 ARM: local timers: switch imx6q to standalone smp_twd

Hi Marc,

Quoted 5 lines · Marc Zyngier

Convert the imx6q platforms to the standalone version of smp_twd.c. Since the timer calibration code requires another timer to be up and running, the actual initialisation is left to the late_timer_init hook.

Quoted 9 lines
---
 arch/arm/mach-imx/Makefile     |    1 -
 arch/arm/mach-imx/localtimer.c |   35 -----------------------------------
 arch/arm/mach-imx/mach-imx6q.c |   12 ++++++++++++
 3 files changed, 12 insertions(+), 36 deletions(-)
 delete mode 100644 arch/arm/mach-imx/localtimer.c

Are we missing 'select ARM_SMP_TWD' for 'config SOC_IMX6Q' in arch/arm/mach-imx/Kconfig?

With that added,

Signature · 2 lines
Regards,
Shawn
#16 lore raw

PATCH v2 12/15 ARM: smp_twd: remove support for non-standalone version

In reply to Marc Zyngier

There is no in-tree platform using both CONFIG_LOCAL_TIMERS and CONFIG_HAVE_ARM_TWD. As such, some code can be removed and some exported functions of smp_twd.c can be made static.

---
 arch/arm/Kconfig                  |    1 -
 arch/arm/include/asm/localtimer.h |   10 ------
 arch/arm/include/asm/smp_twd.h    |    5 ---
 arch/arm/kernel/smp_twd.c         |   65 ++++++++++--------------------------
 4 files changed, 18 insertions(+), 63 deletions(-)
arch/arm/Kconfig +0 -1
index c37410a..c3732bb 100644
@@ -1566,7 +1566,6 @@ config LOCAL_TIMERS
 	bool "Use local timer interrupts"
 	depends on SMP && !ARM_SMP_TWD
 	default y
-	select HAVE_ARM_TWD if (!ARCH_MSM_SCORPIONMP && !EXYNOS4_MCT)
 	help
 	  Enable support for local timers on SMP platforms, rather then the
 	  legacy IPI broadcast method.  Local timers allows the system
arch/arm/include/asm/localtimer.h +0 -10
index c6a1842..5f21c37 100644
@@ -22,21 +22,11 @@ void percpu_timer_setup(void);
 
 #ifdef CONFIG_LOCAL_TIMERS
 
-#ifdef CONFIG_HAVE_ARM_TWD
-
-#include "smp_twd.h"
-
-#define local_timer_stop(c)	twd_timer_stop((c))
-
-#else
-
 /*
  * Stop the local timer
  */
 void local_timer_stop(struct clock_event_device *);
 
-#endif
-
 /*
  * Setup a local timer interrupt for a CPU.
  */
arch/arm/include/asm/smp_twd.h +0 -5
index 09c3b71..1479a6f 100644
@@ -18,14 +18,9 @@
 #define TWD_TIMER_CONTROL_PERIODIC	(1 << 1)
 #define TWD_TIMER_CONTROL_IT_ENABLE	(1 << 2)
 
-struct clock_event_device;
 struct resource;
 struct of_device_id;
 
-extern void __iomem *twd_base;
-
-void twd_timer_setup(struct clock_event_device *);
-void twd_timer_stop(struct clock_event_device *);
 #ifdef CONFIG_HAVE_ARM_TWD
 int twd_timer_register(struct resource *res, int res_nr);
 int twd_timer_of_init(const struct of_device_id *twd_of_match);
arch/arm/kernel/smp_twd.c +18 -47

127 lines not on this page · raw message

Signature · 1 line
1.7.7.1
#17 lore raw

PATCH v2 13/15 ARM: local timers: make MCT timer standalone

In reply to Marc Zyngier

Following the same pattern used for smp_twd, allow the MCT timers to be built in standalone, without relying on the CONFIG_LOCAL_TIMER infrastructure and use a CPU notifier block to stop or start the timer on the right CPU.

---
 arch/arm/Kconfig           |    2 +-
 arch/arm/mach-exynos/mct.c |   85 ++++++++++++++++++++++++++++++-------------
 2 files changed, 60 insertions(+), 27 deletions(-)
arch/arm/Kconfig +1 -1
index c3732bb..f5563c5 100644
@@ -1564,7 +1564,7 @@ config HOTPLUG_CPU
 
 config LOCAL_TIMERS
 	bool "Use local timer interrupts"
-	depends on SMP && !ARM_SMP_TWD
+	depends on SMP && !ARM_SMP_TWD && !EXYNOS4_MCT
 	default y
 	help
 	  Enable support for local timers on SMP platforms, rather then the
arch/arm/mach-exynos/mct.c +59 -26

172 lines not on this page · raw message

Signature · 1 line
1.7.7.1
#18 lore raw

PATCH v2 14/15 ARM: local timers: make MSM timers standalone

In reply to Marc Zyngier

Following the same pattern used for smp_twd, allow the MSM timers to be built in standalone, without relying on the CONFIG_LOCAL_TIMER infrastructure and use a CPU notifier block to stop or start the timer on the secondary CPU.

Cc David Brown <[email protected]>
Cc Stephen Boyd <[email protected]>
---
 arch/arm/Kconfig          |    2 +-
 arch/arm/mach-msm/timer.c |   92 +++++++++++++++++++++++++++++++++-----------
 2 files changed, 70 insertions(+), 24 deletions(-)
arch/arm/Kconfig +1 -1
index f5563c5..cea5e72 100644
@@ -1564,7 +1564,7 @@ config HOTPLUG_CPU
 
 config LOCAL_TIMERS
 	bool "Use local timer interrupts"
-	depends on SMP && !ARM_SMP_TWD && !EXYNOS4_MCT
+	depends on SMP && !ARM_SMP_TWD && !EXYNOS4_MCT && !MSM
 	default y
 	help
 	  Enable support for local timers on SMP platforms, rather then the
arch/arm/mach-msm/timer.c +69 -23

160 lines not on this page · raw message

Signature · 1 line
1.7.7.1
#19 lore raw

PATCH v2 15/15 ARM: local timers: Remove CONFIG_LOCAL_TIMERS support

In reply to Marc Zyngier

Local timer support in arch/arm is now completely unused, as all in-tree platforms are using standalone timers.

It allows us to simplify the code, only preserving the broadcast timer. The broadcast timer is always installed, and we leave it up to the kernel to pick the more suitable timer (usually the one with the highest priority).

---
 arch/arm/Kconfig                  |   10 -------
 arch/arm/include/asm/localtimer.h |   47 --------------------------------
 arch/arm/kernel/smp.c             |   54 +++++++++----------------------------
 3 files changed, 13 insertions(+), 98 deletions(-)
 delete mode 100644 arch/arm/include/asm/localtimer.h
arch/arm/Kconfig +0 -10
index cea5e72..46ce570 100644
@@ -1562,16 +1562,6 @@ config HOTPLUG_CPU
 	  Say Y here to experiment with turning CPUs off and on.  CPUs
 	  can be controlled through /sys/devices/system/cpu.
 
-config LOCAL_TIMERS
-	bool "Use local timer interrupts"
-	depends on SMP && !ARM_SMP_TWD && !EXYNOS4_MCT && !MSM
-	default y
-	help
-	  Enable support for local timers on SMP platforms, rather then the
-	  legacy IPI broadcast method.  Local timers allows the system
-	  accounting to be spread across the timer interval, preventing a
-	  "thundering herd" at every timer tick.
-
 source kernel/Kconfig.preempt
 
 config HZ
arch/arm/include/asm/localtimer.h deleted +0 -47

47 lines not on this page · raw message

arch/arm/kernel/smp.c +13 -41

114 lines not on this page · raw message

Signature · 1 line
1.7.7.1
#20 lore raw

v2 cover Make SMP timers standalone

In reply to Marc Zyngier
Quoted 3 lines · Marc Zyngier

The proposal is to convert local timer drivers to be "standalone" (not relying on the local timer infrastructure) and to use a CPU notifier to have the timer brought up or down on non-boot CPUs.

You do realise that it's pointless having local timers on non-SMP hardware. On such hardware, you have a single timer instead.

You're also aware I assume that local timers are different from the global timer itself, and require to have additional callbacks for broadcasting the global timer tick?

There is a reason why local timers _use_ the common local timer clock event stuff.

#21 lore raw

v2 cover Make SMP timers standalone

On 22/12/11 19:32, Russell King - ARM Linux wrote:

Hi Russell,

Quoted 7 lines · Marc Zyngier
Quoted 3 lines

The proposal is to convert local timer drivers to be "standalone" (not relying on the local timer infrastructure) and to use a CPU notifier to have the timer brought up or down on non-boot CPUs.

You do realise that it's pointless having local timers on non-SMP hardware. On such hardware, you have a single timer instead.

I do. But on some non-SMP platforms, the local timer and the global timer can actually be the same (MSM is one example of this, and the UP version of the Cortex A15 is another).

Quoted 3 lines

You're also aware I assume that local timers are different from the global timer itself, and require to have additional callbacks for broadcasting the global timer tick?

I was under the impression that we either have the global timer together with broadcasting or the local timers. Completely removing the broadcast callback doesn't seem to generate any ill effect as long as the local timers are used instead of the global timer (which of course requires broadcast in the SMP configuration).

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

v2 cover Make SMP timers standalone

Quoted 10 lines · Marc Zyngier
Quoted 3 lines · Russell King - ARM Linux

You're also aware I assume that local timers are different from the global timer itself, and require to have additional callbacks for broadcasting the global timer tick?

I was under the impression that we either have the global timer together with broadcasting or the local timers. Completely removing the broadcast callback doesn't seem to generate any ill effect as long as the local timers are used instead of the global timer (which of course requires broadcast in the SMP configuration).

I believe even if you have local timers, there are situations where the these will be disabled and the kernel will switch to broadcasting from a global timer tick. I think such a scenario would be like that encountered with OMAP, where suspending a CPU stops its TWD - meaning that the TWD can't be used to wake the CPU from one of the deeper idle states.

#23 lore raw

v2 cover Make SMP timers standalone

Quoted 12 lines · Russell King - ARM Linux
Quoted 10 lines · Marc Zyngier
Quoted 3 lines · Russell King - ARM Linux

You're also aware I assume that local timers are different from the global timer itself, and require to have additional callbacks for broadcasting the global timer tick?

I was under the impression that we either have the global timer together with broadcasting or the local timers. Completely removing the broadcast callback doesn't seem to generate any ill effect as long as the local timers are used instead of the global timer (which of course requires broadcast in the SMP configuration).

Quoted 5 lines

I believe even if you have local timers, there are situations where the these will be disabled and the kernel will switch to broadcasting from a global timer tick. ?I think such a scenario would be like that encountered with OMAP, where suspending a CPU stops its TWD - meaning that the TWD can't be used to wake the CPU from one of the deeper idle states.

This is true also for the Ux500.

The situation occurs as soon as you want to gate off or power down the CPU clock/power domain, in which the TWD is sythesized.

However IIRC this situation does not occur in the ARM reference designs, notably Versatile Express since it simply isn't designed to be power-agressive in this way and does not gate the clock or power down the CPU power domain, it's always on, always clocked (albeit with shifting frequency).

The Vexpress seem to register a clockevent for its SP804 timer, and even though I've never used this machine I guess it would tick a few ticks during boot and then as TWD is registered it switches to that (due to higher .rate) and no IRQ is ever fired on the SP804 again.

Does this correspond to what is seen in /proc/interrupts on the Vexpress?

And does the system really work if you simply delete the code registering the SP804 clockevent from mach-vexpress/ct-ca9x4.c?

Yours,
Linus Walleij

#24 lore raw

v2 cover Make SMP timers standalone

Quoted 6 lines · Linus Walleij

However IIRC this situation does not occur in the ARM reference designs, notably Versatile Express since it simply isn't designed to be power-agressive in this way and does not gate the clock or power down the CPU power domain, it's always on, always clocked (albeit with shifting frequency).

Quoted 8 lines

The Vexpress seem to register a clockevent for its SP804 timer, and even though I've never used this machine I guess it would tick a few ticks during boot and then as TWD is registered it switches to that (due to higher .rate) and no IRQ is ever fired on the SP804 again.

Does this correspond to what is seen in /proc/interrupts on the Vexpress?

Yes. You get about 8 ticks worth of SP804, and then switch to TWD for good.

Quoted 3 lines

And does the system really work if you simply delete the code registering the SP804 clockevent from mach-vexpress/ct-ca9x4.c?

No, because you need the global timer to calibrate the TWD on this platform. But on the VE with a Cortex-A15 tile, the system works perfectly with the architected timers being the only one in the system (the SP804 is left unconfigured).

But now that your cpufreq-aware patches are in -next, I can boot a Panda without a single tick of the global timer (OMAP4 provides the "smp-twd" clock).

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

v2 cover Make SMP timers standalone

Quoted 22 lines · Marc Zyngier
Quoted 6 lines · Linus Walleij

However IIRC this situation does not occur in the ARM reference designs, notably Versatile Express since it simply isn't designed to be power-agressive in this way and does not gate the clock or power down the CPU power domain, it's always on, always clocked (albeit with shifting frequency).

Quoted 8 lines

The Vexpress seem to register a clockevent for its SP804 timer, and even though I've never used this machine I guess it would tick a few ticks during boot and then as TWD is registered it switches to that (due to higher .rate) and no IRQ is ever fired on the SP804 again.

Does this correspond to what is seen in /proc/interrupts on the Vexpress?

Yes. You get about 8 ticks worth of SP804, and then switch to TWD for good.

Quoted 3 lines

And does the system really work if you simply delete the code registering the SP804 clockevent from mach-vexpress/ct-ca9x4.c?

Quoted 9 lines

No, because you need the global timer to calibrate the TWD on this platform. But on the VE with a Cortex-A15 tile, the system works perfectly with the architected timers being the only one in the system (the SP804 is left unconfigured).

But now that your cpufreq-aware patches are in -next, I can boot a Panda without a single tick of the global timer (OMAP4 provides the "smp-twd" clock).

That's only because CPUIDLE low power states are not enabled. You do that and without global timer, system will just die

#26 lore raw

v2 cover Make SMP timers standalone

Quoted 28 lines · Santosh
Quoted 27 lines · Marc Zyngier
Quoted 6 lines · Linus Walleij

However IIRC this situation does not occur in the ARM reference designs, notably Versatile Express since it simply isn't designed to be power-agressive in this way and does not gate the clock or power down the CPU power domain, it's always on, always clocked (albeit with shifting frequency).

Quoted 8 lines

The Vexpress seem to register a clockevent for its SP804 timer, and even though I've never used this machine I guess it would tick a few ticks during boot and then as TWD is registered it switches to that (due to higher .rate) and no IRQ is ever fired on the SP804 again.

Does this correspond to what is seen in /proc/interrupts on the Vexpress?

Yes. You get about 8 ticks worth of SP804, and then switch to TWD for good.

Quoted 3 lines

And does the system really work if you simply delete the code registering the SP804 clockevent from mach-vexpress/ct-ca9x4.c?

No, because you need the global timer to calibrate the TWD on this platform. But on the VE with a Cortex-A15 tile, the system works perfectly with the architected timers being the only one in the system (the SP804 is left unconfigured).

Quoted 6 lines
Quoted 4 lines

But now that your cpufreq-aware patches are in -next, I can boot a Panda without a single tick of the global timer (OMAP4 provides the "smp-twd" clock).

That's only because CPUIDLE low power states are not enabled. You do that and without global timer, system will just die

Global timer is still present, configured and enabled. The kernel just happens to select TWD as a better timer. Should TWD be turned off, gp_timer will be selected again.

This is also what happens with the current implementation, and my patches don't change that.

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

v2 cover Make SMP timers standalone

Quoted 3 lines · Marc Zyngier

Global timer is still present, configured and enabled. The kernel just happens to select TWD as a better timer. Should TWD be turned off, gp_timer will be selected again.

And at that point, the core time keeping code will find a local timer clock event structure and expect it's broadcast method to be implemented and working, as I described in my initial reply.

Quoted 2 lines

This is also what happens with the current implementation, and my patches don't change that.

Yes they do, because they omit the broadcast method.

Look, local timers *are* special. They're not the same as global timers. They're treated differently. Ripping out the local timer setup stuff from the SMP code is not the right solution, especially when we've already got a separation of the local timer core from the hardware implementation.

#28 lore raw

v2 cover Make SMP timers standalone

Quoted 5 lines · Russell King - ARM Linux
Quoted 3 lines · Marc Zyngier

Global timer is still present, configured and enabled. The kernel just happens to select TWD as a better timer. Should TWD be turned off, gp_timer will be selected again.

Quoted 8 lines

And at that point, the core time keeping code will find a local timer clock event structure and expect it's broadcast method to be implemented and working, as I described in my initial reply.

Quoted 2 lines

This is also what happens with the current implementation, and my patches don't change that.

Yes they do, because they omit the broadcast method.

I forgot to mention I restored this functionality after you pointed that out (I made smp_timer_broadcast a global symbol).

Quoted 5 lines

Look, local timers *are* special. They're not the same as global timers. They're treated differently. Ripping out the local timer setup stuff from the SMP code is not the right solution, especially when we've already got a separation of the local timer core from the hardware implementation.

OK. I'll try to work out something different.

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

v2 cover Make SMP timers standalone

Quoted 8 lines · Marc Zyngier
Quoted 5 lines · Russell King - ARM Linux

Look, local timers *are* special. They're not the same as global timers. They're treated differently. Ripping out the local timer setup stuff from the SMP code is not the right solution, especially when we've already got a separation of the local timer core from the hardware implementation.

OK. I'll try to work out something different.

Why? What's wrong with the existing structure?

If you want to use the TWD as a global timer, that's easy to do:

static struct clock_event_device twd_global_ce = {
.irq = whatever_irq,
.cpumask = cpu_mask_all,
};

static int __init twd_global_timer(void)

{
	twd_base = ioremap(twd_phys, SZ_4K);
	if (!twd_base)
		return -ENOMEM;
	twd_timer_setup(&twd_global_ce);
	return 0;
}

And no need to mess around with the local timer structure in arch/arm/kernel/smp.c.

#30 lore raw

v2 cover Make SMP timers standalone

Quoted 11 lines · Russell King - ARM Linux
Quoted 8 lines · Marc Zyngier
Quoted 5 lines · Russell King - ARM Linux

Look, local timers *are* special. They're not the same as global timers. They're treated differently. Ripping out the local timer setup stuff from the SMP code is not the right solution, especially when we've already got a separation of the local timer core from the hardware implementation.

OK. I'll try to work out something different.

Why? What's wrong with the existing structure?

My main goal here is not to use a local timer as a global timer, but rather to be able to support multiple local timer implementations in the same kernel (TWD, MCT...). The "local timer on UP" is merely a consequence.

I could come up with another registration interface that fits into the existing structure, but I thought something could be done with what we currently have.

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

v2 cover Make SMP timers standalone

Quoted 13 lines · Marc Zyngier
Quoted 11 lines · Russell King - ARM Linux
Quoted 8 lines · Marc Zyngier
Quoted 5 lines · Russell King - ARM Linux

Look, local timers *are* special. They're not the same as global timers. They're treated differently. Ripping out the local timer setup stuff from the SMP code is not the right solution, especially when we've already got a separation of the local timer core from the hardware implementation.

OK. I'll try to work out something different.

Why? What's wrong with the existing structure?

Quoted 7 lines

My main goal here is not to use a local timer as a global timer, but rather to be able to support multiple local timer implementations in the same kernel (TWD, MCT...). The "local timer on UP" is merely a consequence.

I could come up with another registration interface that fits into the existing structure, but I thought something could be done with what we currently have.

That's easy - but the solution depends on exactly how you're trying to solve it.

In local_timer.h:

struct local_timer {
	int (*setup)(struct clock_event_device *);
	void (*stop)(struct clock_event_device *);
};

int local_timer_register(struct local_timer *);

In arch/arm/kernel/smp.c:

static struct local_timer *local_timer;

int local_timer_register(struct local_timer *lt)

{
	if (local_timer)
		return -EBUSY;
	local_timer = lt;
	return 0;
}

static int local_timer_setup(struct clock_event_device *ce)

{
	return local_timer ? local_timer->setup(ce) : -ENXIO;
}

static void local_timer_stop(struct clock_event_device *ce)

{
	if (local_timer)
		local_timer->stop(ce);
}

And, for twd:

struct local_timer twd_local_timer = {
.setup = twd_timer_setup,
.stop = twd_timer_stop,
};

But... it's not quite that simple because platforms need to intercept the local_timer_setup() call to do platform specific things - such as finding the twd base, and setting the twd IRQ. That can be solved by moving that out of platform code (why is it there in the first place?) into smp_twd.c, and providing twd_local_timer_dt.

#32 lore raw

v2 cover Make SMP timers standalone

Quoted 5 lines · Russell King - ARM Linux

But... it's not quite that simple because platforms need to intercept the local_timer_setup() call to do platform specific things - such as finding the twd base, and setting the twd IRQ. That can be solved by moving that out of platform code (why is it there in the first place?) into smp_twd.c, and providing twd_local_timer_dt.

And that's something we really should do anyway - we already have two implementations which are virtually identical to each other for no real reason other than people like to mess around in their own platform stuff rather than solving problems at higher levels.

So, I'll queue this patch after the next merge window.

Note: there's no need for that WARN_ON and subsequent oops in each of these setup functions - it can return an error, in which case we'll fall back to a broadcasted tick for the CPU.

8<---------
From: Russell King <[email protected]>
ARM: TWD: Move DT code into smp_twd.c

Rather than have each platform implement their own DT veneer to discover the base address and IRQ for their TWD, move this code into the TWD driver itself.

---
 arch/arm/include/asm/smp_twd.h      |    1 +
 arch/arm/kernel/smp_twd.c           |   21 +++++++++++++++++++++
 arch/arm/mach-highbank/localtimer.c |   14 +-------------
 arch/arm/mach-imx/localtimer.c      |   14 +-------------
 4 files changed, 24 insertions(+), 26 deletions(-)
arch/arm/include/asm/smp_twd.h +1 -0
index ef9ffba9..855f58e 100644
@@ -23,6 +23,7 @@ struct clock_event_device;
 extern void __iomem *twd_base;
 
 void twd_timer_setup(struct clock_event_device *);
+int twd_timer_setup_dt(struct clock_event_device *);
 void twd_timer_stop(struct clock_event_device *);
 
 #endif
arch/arm/kernel/smp_twd.c +21 -0
index c8e9385..f43f039 100644
@@ -20,6 +20,9 @@
 #include <linux/clockchips.h>
 #include <linux/irq.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 
 #include <asm/smp_twd.h>
 #include <asm/localtimer.h>
@@ -266,3 +269,21 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
 					0xf, 0xffffffff);
 	enable_percpu_irq(clk->irq, 0);
 }
+
+int __cpuinit twd_timer_setup_dt(struct clock_event_device *clk)
+{
+	struct device_node *np;
+
+	np = of_find_compatible_node(NULL, NULL, "arm,smp-twd");
+	if (np) {
+		if (!twd_base) {
+			twd_base = of_iomap(np, 0);
+			if (!twd_base)
+				return -ENOMEM;
+		}
+		evt->irq = irq_of_parse_and_map(np, 0);
+	}
+	twd_timer_setup(evt);
+
+	return 0;
+}
arch/arm/mach-highbank/localtimer.c +1 -13
index 5a00e79..1b6c0d1 100644
@@ -16,9 +16,6 @@
  */
 #include <linux/init.h>
 #include <linux/clockchips.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
 
 #include <asm/smp_twd.h>
 
@@ -27,14 +24,5 @@
  */
 int __cpuinit local_timer_setup(struct clock_event_device *evt)
 {
-	struct device_node *np;
-
-	np = of_find_compatible_node(NULL, NULL, "arm,smp-twd");
-	if (!twd_base) {
-		twd_base = of_iomap(np, 0);
-		WARN_ON(!twd_base);
-	}
-	evt->irq = irq_of_parse_and_map(np, 0);
-	twd_timer_setup(evt);
-	return 0;
+	return twd_timer_setup_dt(evt);
 }
arch/arm/mach-imx/localtimer.c +1 -13
index 3a16351..1252c22 100644
@@ -12,8 +12,6 @@
 
 #include <linux/init.h>
 #include <linux/clockchips.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
 #include <asm/smp_twd.h>
 
 /*
@@ -21,15 +19,5 @@
  */
 int __cpuinit local_timer_setup(struct clock_event_device *evt)
 {
-	struct device_node *np;
-
-	np = of_find_compatible_node(NULL, NULL, "arm,smp-twd");
-	if (!twd_base) {
-		twd_base = of_iomap(np, 0);
-		WARN_ON(!twd_base);
-	}
-	evt->irq = irq_of_parse_and_map(np, 0);
-	twd_timer_setup(evt);
-
-	return 0;
+	return twd_timer_setup_dt(evt);
 }
#33 lore raw

v2 cover Make SMP timers standalone

In reply to Marc Zyngier
Quoted 36 lines · Marc Zyngier
Quoted 28 lines · Santosh
Quoted 27 lines · Marc Zyngier
Quoted 6 lines · Linus Walleij

However IIRC this situation does not occur in the ARM reference designs, notably Versatile Express since it simply isn't designed to be power-agressive in this way and does not gate the clock or power down the CPU power domain, it's always on, always clocked (albeit with shifting frequency).

Quoted 8 lines

The Vexpress seem to register a clockevent for its SP804 timer, and even though I've never used this machine I guess it would tick a few ticks during boot and then as TWD is registered it switches to that (due to higher .rate) and no IRQ is ever fired on the SP804 again.

Does this correspond to what is seen in /proc/interrupts on the Vexpress?

Yes. You get about 8 ticks worth of SP804, and then switch to TWD for good.

Quoted 3 lines

And does the system really work if you simply delete the code registering the SP804 clockevent from mach-vexpress/ct-ca9x4.c?

No, because you need the global timer to calibrate the TWD on this platform. But on the VE with a Cortex-A15 tile, the system works perfectly with the architected timers being the only one in the system (the SP804 is left unconfigured).

Quoted 6 lines
Quoted 4 lines

But now that your cpufreq-aware patches are in -next, I can boot a Panda without a single tick of the global timer (OMAP4 provides the "smp-twd" clock).

That's only because CPUIDLE low power states are not enabled. You do that and without global timer, system will just die

Quoted 7 lines

Global timer is still present, configured and enabled. The kernel just happens to select TWD as a better timer. Should TWD be turned off, gp_timer will be selected again.

This is also what happens with the current implementation, and my patches don't change that.

Great. Thanks for clarifying Marc.

Regards
Santosh

#34 lore raw

v2 cover Make SMP timers standalone

In reply to Russell King - ARM Linux
Quoted 12 lines · Russell King - ARM Linux
Quoted 10 lines · Marc Zyngier
Quoted 3 lines · Russell King - ARM Linux

You're also aware I assume that local timers are different from the global timer itself, and require to have additional callbacks for broadcasting the global timer tick?

I was under the impression that we either have the global timer together with broadcasting or the local timers. Completely removing the broadcast callback doesn't seem to generate any ill effect as long as the local timers are used instead of the global timer (which of course requires broadcast in the SMP configuration).

Quoted 5 lines

I believe even if you have local timers, there are situations where the these will be disabled and the kernel will switch to broadcasting from a global timer tick. I think such a scenario would be like that encountered with OMAP, where suspending a CPU stops its TWD - meaning that the TWD can't be used to wake the CPU from one of the deeper idle states.

Yes, being able to wake up is definitely a good reason to keep a global timer around, not to mention other artifacts (TWD calibration being one, though on its way out thanks to LinusW patch series).

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

v2 cover Make SMP timers standalone

Quoted 19 lines · Marc Zyngier
Quoted 12 lines · Russell King - ARM Linux
Quoted 10 lines · Marc Zyngier
Quoted 3 lines · Russell King - ARM Linux

You're also aware I assume that local timers are different from the global timer itself, and require to have additional callbacks for broadcasting the global timer tick?

I was under the impression that we either have the global timer together with broadcasting or the local timers. Completely removing the broadcast callback doesn't seem to generate any ill effect as long as the local timers are used instead of the global timer (which of course requires broadcast in the SMP configuration).

Quoted 5 lines

I believe even if you have local timers, there are situations where the these will be disabled and the kernel will switch to broadcasting from a global timer tick. ?I think such a scenario would be like that encountered with OMAP, where suspending a CPU stops its TWD - meaning that the TWD can't be used to wake the CPU from one of the deeper idle states.

Quoted 4 lines

Yes, being able to wake up is definitely a good reason to keep a global timer around, not to mention other artifacts (TWD calibration being one, though on its way out thanks to LinusW patch series).

Catching up bit late on this tread.
I just want to echo the fact that we always need the wakeup capable clock-event till the local timers themselves can wakup the CPU from low power states.

Regards
Santosh

#36 lore raw

v2 cover Make SMP timers standalone

In reply to Marc Zyngier
Quoted 9 lines · Marc Zyngier

On 22/12/11 19:32, Russell King - ARM Linux wrote:

Hi Russell,

Quoted 5 lines · Marc Zyngier
Quoted 3 lines

The proposal is to convert local timer drivers to be "standalone" (not relying on the local timer infrastructure) and to use a CPU notifier to have the timer brought up or down on non-boot CPUs.

Quoted 6 lines
Quoted 2 lines

You do realise that it's pointless having local timers on non-SMP hardware. On such hardware, you have a single timer instead.

I do. But on some non-SMP platforms, the local timer and the global timer can actually be the same (MSM is one example of this, and the UP version of the Cortex A15 is another).

On SMP MSM, we use the CPU0 local timer as the global timer. They are the same on non-SMP as well, I guess, but as Russell says, I'm not sure what the concept of a local timer would mean on non-SMP.

David

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.
#37 lore raw

v2 cover Make SMP timers standalone

Quoted 7 lines · David Brown
Quoted 3 lines · Marc Zyngier

I do. But on some non-SMP platforms, the local timer and the global timer can actually be the same (MSM is one example of this, and the UP version of the Cortex A15 is another).

On SMP MSM, we use the CPU0 local timer as the global timer. ?They are the same on non-SMP as well,

Does this mean your CPU0 local timer is always on, always clocked? And do you use ARMs SMP TWD IP block for that?

Quoted 2 lines

I guess, but as Russell says, I'm not
sure what the concept of a local timer would mean on non-SMP.

I think this looks like one big misunderstanding. I understood it as the SMP TWD block is synthesized also on UP silicon, i.e. same hardware, and so it will need to use the driver from arch/arm/kernel/smp_twd.c, however there is nothing local about that apart from being in close locality of the CPU.

Let us talk about the SMP TWD timer block for A8/A9 systems if that is what it's all about (is it? maybe I'm confused too...) and architectured timers for A15.

Linus Walleij

#38 lore raw

v2 cover Make SMP timers standalone

Quoted 5 lines · Linus Walleij

I think this looks like one big misunderstanding. I understood it as the SMP TWD block is synthesized also on UP silicon, i.e. same hardware, and so it will need to use the driver from arch/arm/kernel/smp_twd.c, however there is nothing local about that apart from being in close locality of the CPU.

Yes indeed. The TWD code is architected to plug into the local timer code via a set of well defined hooks.

It's entirely possible to call the TWD setup function with a non-local timer clock event structure if you have a TWD which is a global timer. The percpu stuff for storage will just work on UP systems, so that's not a concern. What could be is the percpu IRQ stuff, which presumably wouldn't be available on non-SMP systems.

Apart from that, I think the current architecture is right - it separates the hardware timer code from the local-timer specifics, and allows the hardware timer driver to be re-used if needed.

Trying to make local timers as a general rule work as global timers is, I think, a big mistake. I've no problem with making a local timer hardware _implementation_ work as a global timer though.

#39 lore raw

v2 cover Make SMP timers standalone

In reply to Linus Walleij
Quoted 10 lines · Linus Walleij
Quoted 6 lines · David Brown
Quoted 3 lines · Marc Zyngier

I do. But on some non-SMP platforms, the local timer and the global timer can actually be the same (MSM is one example of this, and the UP version of the Cortex A15 is another).

On SMP MSM, we use the CPU0 local timer as the global timer. They are the same on non-SMP as well,

Does this mean your CPU0 local timer is always on, always clocked? And do you use ARMs SMP TWD IP block for that?

Yes, CPU0's local timer is always on. We use it as a global clocksource, as well
as for udelay on both cores. It is not ARM's SMP TWD block, it is our own. The
timer blocks can each be read from both CPUs, but can only generate IRQs to one
or the other.

Jeff