All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/15] Make SMP timers standalone
@ 2011-12-22 17:27 Marc Zyngier
  2011-12-22 17:27 ` [PATCH v2 01/15] ARM: local timers: allow smp_twd to be used standalone Marc Zyngier
                   ` (15 more replies)
  0 siblings, 16 replies; 40+ messages in thread
From: Marc Zyngier @ 2011-12-22 17:27 UTC (permalink / raw)
  To: linux-arm-kernel

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.

>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

-- 
1.7.7.1

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

* [PATCH v2 01/15] ARM: local timers: allow smp_twd to be used standalone
  2011-12-22 17:27 [PATCH v2 00/15] Make SMP timers standalone Marc Zyngier
@ 2011-12-22 17:27 ` Marc Zyngier
  2011-12-22 20:38   ` Russell King - ARM Linux
  2011-12-22 17:27 ` [PATCH v2 02/15] ARM: smp_twd: add device tree support Marc Zyngier
                   ` (14 subsequent siblings)
  15 siblings, 1 reply; 40+ messages in thread
From: Marc Zyngier @ 2011-12-22 17:27 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 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(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 6f3e186..c37410a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -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
diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h
index ef9ffba9..934f1bc 100644
--- a/arch/arm/include/asm/smp_twd.h
+++ b/arch/arm/include/asm/smp_twd.h
@@ -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
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 2442bbb..dedbdb4 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -13,11 +13,13 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/smp.h>
+#include <linux/cpu.h>
 #include <linux/jiffies.h>
 #include <linux/clockchips.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 
+#include <asm/smp_plat.h>
 #include <asm/smp_twd.h>
 #include <asm/localtimer.h>
 #include <asm/hardware/gic.h>
@@ -172,7 +174,7 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
 	clk->name = "local_timer";
 	clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
 			CLOCK_EVT_FEAT_C3STOP;
-	clk->rating = 350;
+	clk->rating = 450;	/* Make sure this is higher than broadcast */
 	clk->set_mode = twd_set_mode;
 	clk->set_next_event = twd_set_next_event;
 	clk->shift = 20;
@@ -187,3 +189,78 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
 
 	enable_percpu_irq(clk->irq, 0);
 }
+
+#ifdef CONFIG_ARM_SMP_TWD
+static struct clock_event_device __percpu *twd_clock_event;
+static int twd_ppi;
+
+static void __cpuinit twd_setup(struct clock_event_device *clk)
+{
+	clk->cpumask = cpumask_of(smp_processor_id());
+	clk->irq = twd_ppi;
+	twd_timer_setup(clk);
+}
+
+static void __cpuinit twd_teardown(void *data)
+{
+	struct clock_event_device *clk = data;
+	twd_timer_stop(clk);
+}
+
+static int __cpuinit twd_cpu_notify(struct notifier_block *self,
+				    unsigned long action, void *data)
+{
+	int cpu = (int)data;
+	struct clock_event_device *clk = per_cpu_ptr(twd_clock_event, cpu);
+
+	switch (action) {
+	case CPU_STARTING:
+	case CPU_STARTING_FROZEN:
+		twd_setup(clk);
+		break;
+
+	case CPU_DOWN_PREPARE:
+	case CPU_DOWN_PREPARE_FROZEN:
+		smp_call_function_single(cpu, twd_teardown, clk, 1);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata twd_cpu_nb = {
+	.notifier_call = twd_cpu_notify,
+};
+
+int __init twd_timer_register(struct resource *res, int res_nr)
+{
+	struct clock_event_device *clk;
+
+	if (!is_smp())
+		return -ENODEV;
+
+	if (res_nr != 2 || res[1].start < 0)
+		return -EINVAL;
+
+	if (twd_base)
+		return -EBUSY;
+
+	twd_ppi		= res[1].start;
+	twd_base	= ioremap(res[0].start, resource_size(&res[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);
+
+	register_cpu_notifier(&twd_cpu_nb);
+
+	return 0;
+}
+#endif
-- 
1.7.7.1

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

* [PATCH v2 02/15] ARM: smp_twd: add device tree support
  2011-12-22 17:27 [PATCH v2 00/15] Make SMP timers standalone Marc Zyngier
  2011-12-22 17:27 ` [PATCH v2 01/15] ARM: local timers: allow smp_twd to be used standalone Marc Zyngier
@ 2011-12-22 17:27 ` Marc Zyngier
  2011-12-22 17:27 ` [PATCH v2 03/15] ARM: local timers: switch realview to standalone smp_twd Marc Zyngier
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Marc Zyngier @ 2011-12-22 17:27 UTC (permalink / raw)
  To: linux-arm-kernel

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

Cc: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 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

diff --git a/Documentation/devicetree/bindings/arm/twd.txt b/Documentation/devicetree/bindings/arm/twd.txt
new file mode 100644
index 0000000..a9d5587
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/twd.txt
@@ -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>;
+	};
diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h
index 934f1bc..09c3b71 100644
--- a/arch/arm/include/asm/smp_twd.h
+++ b/arch/arm/include/asm/smp_twd.h
@@ -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
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index dedbdb4..98a6a59 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -18,6 +18,8 @@
 #include <linux/clockchips.h>
 #include <linux/irq.h>
 #include <linux/io.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
 
 #include <asm/smp_plat.h>
 #include <asm/smp_twd.h>
@@ -232,13 +234,40 @@ static struct notifier_block __cpuinitdata twd_cpu_nb = {
 	.notifier_call = twd_cpu_notify,
 };
 
-int __init twd_timer_register(struct resource *res, int res_nr)
+static int __init twd_timer_common_init(void)
 {
 	struct clock_event_device *clk;
+	int err;
 
-	if (!is_smp())
-		return -ENODEV;
+	if (!is_smp()) {
+		err = -ENODEV;
+		goto out_free;
+	}
+
+	twd_clock_event	= alloc_percpu(struct clock_event_device);
+	if (!twd_clock_event) {
+		err = -ENOMEM;
+		goto out_free;
+	}
+
+	/* Immediately configure the timer on the boot CPU */
+	clk = per_cpu_ptr(twd_clock_event, smp_processor_id());
+	twd_setup(clk);
+
+	register_cpu_notifier(&twd_cpu_nb);
+
+	return 0;
 
+out_free:
+	iounmap(twd_base);
+	twd_base = NULL;
+	free_percpu(twd_clock_event);
+
+	return err;
+}
+
+int __init twd_timer_register(struct resource *res, int res_nr)
+{
 	if (res_nr != 2 || res[1].start < 0)
 		return -EINVAL;
 
@@ -247,20 +276,30 @@ int __init twd_timer_register(struct resource *res, int res_nr)
 
 	twd_ppi		= res[1].start;
 	twd_base	= ioremap(res[0].start, resource_size(&res[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);
+	if (!twd_base)
 		return -ENOMEM;
-	}
 
-	/* Immediately configure the timer on the boot CPU */
-	clk = per_cpu_ptr(twd_clock_event, smp_processor_id());
-	twd_setup(clk);
+	return twd_timer_common_init();
+}
 
-	register_cpu_notifier(&twd_cpu_nb);
+#ifdef CONFIG_OF
+int __init twd_timer_of_init(const struct of_device_id *twd_of_match)
+{
+	struct device_node *np;
 
-	return 0;
+	np = of_find_matching_node(NULL, twd_of_match);
+	if (!np)
+		return -ENODEV;
+
+	twd_ppi = irq_of_parse_and_map(np, 0);
+	if (!twd_ppi)
+		return -EINVAL;
+
+	twd_base = of_iomap(np, 0);
+	if (!twd_base)
+		return -ENOMEM;
+
+	return twd_timer_common_init();
 }
 #endif
+#endif
-- 
1.7.7.1

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

* [PATCH v2 03/15] ARM: local timers: switch realview to standalone smp_twd
  2011-12-22 17:27 [PATCH v2 00/15] Make SMP timers standalone Marc Zyngier
  2011-12-22 17:27 ` [PATCH v2 01/15] ARM: local timers: allow smp_twd to be used standalone Marc Zyngier
  2011-12-22 17:27 ` [PATCH v2 02/15] ARM: smp_twd: add device tree support Marc Zyngier
@ 2011-12-22 17:27 ` Marc Zyngier
  2011-12-22 17:27 ` [PATCH v2 04/15] ARM: local timers: switch vexpress " Marc Zyngier
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Marc Zyngier @ 2011-12-22 17:27 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 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(-)

diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig
index dba6d0c..135a7ea 100644
--- a/arch/arm/mach-realview/Kconfig
+++ b/arch/arm/mach-realview/Kconfig
@@ -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.
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index f92a920..75cd6ef 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -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;
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
index f035fda..b164772 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -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 = {
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
index 0194b3e..d833935 100644
--- a/arch/arm/mach-realview/realview_pbx.c
+++ b/arch/arm/mach-realview/realview_pbx.c
@@ -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);
 }
 
-- 
1.7.7.1

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

* [PATCH v2 04/15] ARM: local timers: switch vexpress to standalone smp_twd
  2011-12-22 17:27 [PATCH v2 00/15] Make SMP timers standalone Marc Zyngier
                   ` (2 preceding siblings ...)
  2011-12-22 17:27 ` [PATCH v2 03/15] ARM: local timers: switch realview to standalone smp_twd Marc Zyngier
@ 2011-12-22 17:27 ` Marc Zyngier
  2011-12-22 17:27 ` [PATCH v2 05/15] ARM: local timers: remove localtimer.c from plat-versatile Marc Zyngier
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Marc Zyngier @ 2011-12-22 17:27 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/mach-vexpress/Kconfig    |    1 +
 arch/arm/mach-vexpress/ct-ca9x4.c |   29 ++++++++++++++++++++++++++---
 2 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig
index 9311484..13f1606 100644
--- a/arch/arm/mach-vexpress/Kconfig
+++ b/arch/arm/mach-vexpress/Kconfig
@@ -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
diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c
index 2b1e836..9ffa7e9 100644
--- a/arch/arm/mach-vexpress/ct-ca9x4.c
+++ b/arch/arm/mach-vexpress/ct-ca9x4.c
@@ -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)
-- 
1.7.7.1

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

* [PATCH v2 05/15] ARM: local timers: remove localtimer.c from plat-versatile
  2011-12-22 17:27 [PATCH v2 00/15] Make SMP timers standalone Marc Zyngier
                   ` (3 preceding siblings ...)
  2011-12-22 17:27 ` [PATCH v2 04/15] ARM: local timers: switch vexpress " Marc Zyngier
@ 2011-12-22 17:27 ` Marc Zyngier
  2011-12-22 17:27 ` [PATCH v2 06/15] ARM: local timers: switch tegra to standalone smp_twd Marc Zyngier
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Marc Zyngier @ 2011-12-22 17:27 UTC (permalink / raw)
  To: linux-arm-kernel

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

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 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

diff --git a/arch/arm/plat-versatile/Makefile b/arch/arm/plat-versatile/Makefile
index 69714db..a5cb194 100644
--- a/arch/arm/plat-versatile/Makefile
+++ b/arch/arm/plat-versatile/Makefile
@@ -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
diff --git a/arch/arm/plat-versatile/localtimer.c b/arch/arm/plat-versatile/localtimer.c
deleted file mode 100644
index 0fb3961..0000000
--- a/arch/arm/plat-versatile/localtimer.c
+++ /dev/null
@@ -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;
-}
-- 
1.7.7.1

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

* [PATCH v2 06/15] ARM: local timers: switch tegra to standalone smp_twd
  2011-12-22 17:27 [PATCH v2 00/15] Make SMP timers standalone Marc Zyngier
                   ` (4 preceding siblings ...)
  2011-12-22 17:27 ` [PATCH v2 05/15] ARM: local timers: remove localtimer.c from plat-versatile Marc Zyngier
@ 2011-12-22 17:27 ` Marc Zyngier
  2011-12-22 19:22   ` Colin Cross
  2011-12-22 17:27 ` [PATCH v2 07/15] ARM: local timers: switch omap4 " Marc Zyngier
                   ` (9 subsequent siblings)
  15 siblings, 1 reply; 40+ messages in thread
From: Marc Zyngier @ 2011-12-22 17:27 UTC (permalink / raw)
  To: linux-arm-kernel

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 <ccross@android.com>
Cc: Erik Gilling <konkers@android.com>
Cc: Olof Johansson <olof@lixom.net>
Cc: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 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

diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 373652d..f93aa6aa 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -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
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index e120ff5..f7d0443 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -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
diff --git a/arch/arm/mach-tegra/localtimer.c b/arch/arm/mach-tegra/localtimer.c
deleted file mode 100644
index e91d681..0000000
--- a/arch/arm/mach-tegra/localtimer.c
+++ /dev/null
@@ -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;
-}
diff --git a/arch/arm/mach-tegra/timer.c b/arch/arm/mach-tegra/timer.c
index 6366654..0c537b9 100644
--- a/arch/arm/mach-tegra/timer.c
+++ b/arch/arm/mach-tegra/timer.c
@@ -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 = {
-- 
1.7.7.1

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

* [PATCH v2 07/15] ARM: local timers: switch omap4 to standalone smp_twd
  2011-12-22 17:27 [PATCH v2 00/15] Make SMP timers standalone Marc Zyngier
                   ` (5 preceding siblings ...)
  2011-12-22 17:27 ` [PATCH v2 06/15] ARM: local timers: switch tegra to standalone smp_twd Marc Zyngier
@ 2011-12-22 17:27 ` Marc Zyngier
  2011-12-23  6:37   ` Shilimkar, Santosh
  2011-12-22 17:27 ` [PATCH v2 08/15] ARM: local timers: switch shmobile " Marc Zyngier
                   ` (8 subsequent siblings)
  15 siblings, 1 reply; 40+ messages in thread
From: Marc Zyngier @ 2011-12-22 17:27 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Cc: Tony Lindgren <tony@atomide.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 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

diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index cb760ac..ab0c972 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -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
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index fc9b238..27ea7c2 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -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
diff --git a/arch/arm/mach-omap2/timer-mpu.c b/arch/arm/mach-omap2/timer-mpu.c
deleted file mode 100644
index 31c0ac4..0000000
--- a/arch/arm/mach-omap2/timer-mpu.c
+++ /dev/null
@@ -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 <santosh.shilimkar@ti.com>
- *
- * 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;
-}
-
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 9edcd52..a69e686 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -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
-- 
1.7.7.1

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

* [PATCH v2 08/15] ARM: local timers: switch shmobile to standalone smp_twd
  2011-12-22 17:27 [PATCH v2 00/15] Make SMP timers standalone Marc Zyngier
                   ` (6 preceding siblings ...)
  2011-12-22 17:27 ` [PATCH v2 07/15] ARM: local timers: switch omap4 " Marc Zyngier
@ 2011-12-22 17:27 ` Marc Zyngier
  2011-12-22 17:27 ` [PATCH v2 09/15] ARM: local timers: switch ux500 " Marc Zyngier
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Marc Zyngier @ 2011-12-22 17:27 UTC (permalink / raw)
  To: linux-arm-kernel

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 <lethal@linux-sh.org>
Cc: Magnus Damm <magnus.damm@gmail.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 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

diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 0828fab..a46db89 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -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
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile
index 5ca1f9d..85c5166 100644
--- a/arch/arm/mach-shmobile/Makefile
+++ b/arch/arm/mach-shmobile/Makefile
@@ -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
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h
index 4bf82c1..658c6ec 100644
--- a/arch/arm/mach-shmobile/include/mach/common.h
+++ b/arch/arm/mach-shmobile/include/mach/common.h
@@ -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 */
diff --git a/arch/arm/mach-shmobile/localtimer.c b/arch/arm/mach-shmobile/localtimer.c
deleted file mode 100644
index ad9ccc9..0000000
--- a/arch/arm/mach-shmobile/localtimer.c
+++ /dev/null
@@ -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;
-}
diff --git a/arch/arm/mach-shmobile/smp-sh73a0.c b/arch/arm/mach-shmobile/smp-sh73a0.c
index be1ade7..cb5f011 100644
--- a/arch/arm/mach-shmobile/smp-sh73a0.c
+++ b/arch/arm/mach-shmobile/smp-sh73a0.c
@@ -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);
diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c
index 895794b..fad385d 100644
--- a/arch/arm/mach-shmobile/timer.c
+++ b/arch/arm/mach-shmobile/timer.c
@@ -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,
 };
-- 
1.7.7.1

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

* [PATCH v2 09/15] ARM: local timers: switch ux500 to standalone smp_twd
  2011-12-22 17:27 [PATCH v2 00/15] Make SMP timers standalone Marc Zyngier
                   ` (7 preceding siblings ...)
  2011-12-22 17:27 ` [PATCH v2 08/15] ARM: local timers: switch shmobile " Marc Zyngier
@ 2011-12-22 17:27 ` Marc Zyngier
  2011-12-22 17:27 ` [PATCH v2 10/15] ARM: local timers: switch highbank " Marc Zyngier
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Marc Zyngier @ 2011-12-22 17:27 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Acked-by: Linus Walleij <linus.walleij@stericsson.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 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

diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index a3e0c86..f69bd06 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -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
diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile
index 6bd2f45..35b3894 100644
--- a/arch/arm/mach-ux500/Makefile
+++ b/arch/arm/mach-ux500/Makefile
@@ -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
 
diff --git a/arch/arm/mach-ux500/localtimer.c b/arch/arm/mach-ux500/localtimer.c
deleted file mode 100644
index 5ba1133..0000000
--- a/arch/arm/mach-ux500/localtimer.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2008-2009 ST-Ericsson
- * Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
- *
- * 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;
-}
diff --git a/arch/arm/mach-ux500/timer.c b/arch/arm/mach-ux500/timer.c
index aea467d..2518dc8 100644
--- a/arch/arm/mach-ux500/timer.c
+++ b/arch/arm/mach-ux500/timer.c
@@ -8,27 +8,53 @@
 #include <linux/errno.h>
 #include <linux/clksrc-dbx500-prcmu.h>
 
-#include <asm/localtimer.h>
+#include <asm/smp_twd.h>
 
 #include <plat/mtu.h>
 
 #include <mach/setup.h>
 #include <mach/hardware.h>
 
+#ifdef CONFIG_ARM_SMP_TWD
+static struct resource ux500_twd_resources[] __initdata = {
+	{
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_LOCALTIMER,
+		.end	= IRQ_LOCALTIMER,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static void __init ux500_twd_init(void)
+{
+	int err = twd_timer_register(ux500_twd_resources,
+				     ARRAY_SIZE(ux500_twd_resources));
+	if (err)
+		pr_err("twd_timer_register failed %d\n", err);
+}
+
+static void __init ux500_twd_set_base(unsigned long base)
+{
+	ux500_twd_resources[0].start = base;
+	ux500_twd_resources[0].end = base + 0x10;
+}
+#else
+#define ux500_twd_init	NULL
+#define ux500_twd_set_base(b)	do { } while(0)
+#endif
+
 static void __init ux500_timer_init(void)
 {
 	void __iomem *prcmu_timer_base;
 
 	if (cpu_is_u5500()) {
-#ifdef CONFIG_LOCAL_TIMERS
-		twd_base = __io_address(U5500_TWD_BASE);
-#endif
+		ux500_twd_set_base(U5500_TWD_BASE);
 		mtu_base = __io_address(U5500_MTU0_BASE);
 		prcmu_timer_base = __io_address(U5500_PRCMU_TIMER_3_BASE);
 	} else if (cpu_is_u8500()) {
-#ifdef CONFIG_LOCAL_TIMERS
-		twd_base = __io_address(U8500_TWD_BASE);
-#endif
+		ux500_twd_set_base(U8500_TWD_BASE);
 		mtu_base = __io_address(U8500_MTU0_BASE);
 		prcmu_timer_base = __io_address(U8500_PRCMU_TIMER_4_BASE);
 	} else {
@@ -54,6 +80,7 @@ static void __init ux500_timer_init(void)
 
 	nmdk_timer_init();
 	clksrc_dbx500_prcmu_init(prcmu_timer_base);
+	late_time_init = ux500_twd_init;
 }
 
 static void ux500_timer_reset(void)
-- 
1.7.7.1

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

* [PATCH v2 10/15] ARM: local timers: switch highbank to standalone smp_twd
  2011-12-22 17:27 [PATCH v2 00/15] Make SMP timers standalone Marc Zyngier
                   ` (8 preceding siblings ...)
  2011-12-22 17:27 ` [PATCH v2 09/15] ARM: local timers: switch ux500 " Marc Zyngier
@ 2011-12-22 17:27 ` Marc Zyngier
  2011-12-22 17:27 ` [PATCH v2 11/15] ARM: local timers: switch imx6q " Marc Zyngier
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Marc Zyngier @ 2011-12-22 17:27 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Cc: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 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

diff --git a/arch/arm/mach-highbank/Makefile b/arch/arm/mach-highbank/Makefile
index 986958a..f8437dd 100644
--- a/arch/arm/mach-highbank/Makefile
+++ b/arch/arm/mach-highbank/Makefile
@@ -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
diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c
index 804c4a5..6a60919 100644
--- a/arch/arm/mach-highbank/highbank.c
+++ b/arch/arm/mach-highbank/highbank.c
@@ -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 = {
diff --git a/arch/arm/mach-highbank/localtimer.c b/arch/arm/mach-highbank/localtimer.c
deleted file mode 100644
index 5a00e79..0000000
--- a/arch/arm/mach-highbank/localtimer.c
+++ /dev/null
@@ -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;
-}
-- 
1.7.7.1

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

* [PATCH v2 11/15] ARM: local timers: switch imx6q to standalone smp_twd
  2011-12-22 17:27 [PATCH v2 00/15] Make SMP timers standalone Marc Zyngier
                   ` (9 preceding siblings ...)
  2011-12-22 17:27 ` [PATCH v2 10/15] ARM: local timers: switch highbank " Marc Zyngier
@ 2011-12-22 17:27 ` Marc Zyngier
  2011-12-25 13:40   ` Shawn Guo
  2011-12-22 17:27 ` [PATCH v2 12/15] ARM: smp_twd: remove support for non-standalone version Marc Zyngier
                   ` (4 subsequent siblings)
  15 siblings, 1 reply; 40+ messages in thread
From: Marc Zyngier @ 2011-12-22 17:27 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Cc: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 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

diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 88a3966..94cbed6 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -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
diff --git a/arch/arm/mach-imx/localtimer.c b/arch/arm/mach-imx/localtimer.c
deleted file mode 100644
index 3a16351..0000000
--- a/arch/arm/mach-imx/localtimer.c
+++ /dev/null
@@ -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;
-}
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index c257281..85031b8 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -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 = {
-- 
1.7.7.1

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

* [PATCH v2 12/15] ARM: smp_twd: remove support for non-standalone version
  2011-12-22 17:27 [PATCH v2 00/15] Make SMP timers standalone Marc Zyngier
                   ` (10 preceding siblings ...)
  2011-12-22 17:27 ` [PATCH v2 11/15] ARM: local timers: switch imx6q " Marc Zyngier
@ 2011-12-22 17:27 ` Marc Zyngier
  2011-12-22 17:27 ` [PATCH v2 13/15] ARM: local timers: make MCT timer standalone Marc Zyngier
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Marc Zyngier @ 2011-12-22 17:27 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 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(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c37410a..c3732bb 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -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
diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h
index c6a1842..5f21c37 100644
--- a/arch/arm/include/asm/localtimer.h
+++ b/arch/arm/include/asm/localtimer.h
@@ -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.
  */
diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h
index 09c3b71..1479a6f 100644
--- a/arch/arm/include/asm/smp_twd.h
+++ b/arch/arm/include/asm/smp_twd.h
@@ -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);
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 98a6a59..aec1bc1 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -18,21 +18,18 @@
 #include <linux/clockchips.h>
 #include <linux/irq.h>
 #include <linux/io.h>
+#include <linux/interrupt.h>
 #include <linux/of_irq.h>
 #include <linux/of_address.h>
 
 #include <asm/smp_plat.h>
 #include <asm/smp_twd.h>
-#include <asm/localtimer.h>
-#include <asm/hardware/gic.h>
-
-/* set up by the platform code */
-void __iomem *twd_base;
 
+static void __iomem *twd_base;
+static struct clock_event_device __percpu *twd_clock_event;
+static int twd_ppi;
 static unsigned long twd_timer_rate;
 
-static struct clock_event_device __percpu **twd_evt;
-
 static void twd_set_mode(enum clock_event_mode mode,
 			struct clock_event_device *clk)
 {
@@ -87,7 +84,7 @@ int twd_timer_ack(void)
 	return 0;
 }
 
-void twd_timer_stop(struct clock_event_device *clk)
+static void twd_timer_stop(struct clock_event_device *clk)
 {
 	twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
 	disable_percpu_irq(clk->irq);
@@ -134,7 +131,7 @@ static void __cpuinit twd_calibrate_rate(void)
 
 static irqreturn_t twd_handler(int irq, void *dev_id)
 {
-	struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
+	struct clock_event_device *evt = dev_id;
 
 	if (twd_timer_ack()) {
 		evt->event_handler(evt);
@@ -147,28 +144,8 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
 /*
  * Setup the local clock events for a CPU.
  */
-void __cpuinit twd_timer_setup(struct clock_event_device *clk)
+static void __cpuinit twd_timer_setup(struct clock_event_device *clk)
 {
-	struct clock_event_device **this_cpu_clk;
-
-	if (!twd_evt) {
-		int err;
-
-		twd_evt = alloc_percpu(struct clock_event_device *);
-		if (!twd_evt) {
-			pr_err("twd: can't allocate memory\n");
-			return;
-		}
-
-		err = request_percpu_irq(clk->irq, twd_handler,
-					 "twd", twd_evt);
-		if (err) {
-			pr_err("twd: can't register interrupt %d (%d)\n",
-			       clk->irq, err);
-			return;
-		}
-	}
-
 	twd_calibrate_rate();
 
 	__raw_writel(0, twd_base + TWD_TIMER_CONTROL);		
@@ -183,26 +160,14 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
 	clk->mult = div_sc(twd_timer_rate, NSEC_PER_SEC, clk->shift);
 	clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
 	clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
-
-	this_cpu_clk = __this_cpu_ptr(twd_evt);
-	*this_cpu_clk = clk;
+	clk->cpumask = cpumask_of(smp_processor_id());
+	clk->irq = twd_ppi;
 
 	clockevents_register_device(clk);
 
 	enable_percpu_irq(clk->irq, 0);
 }
 
-#ifdef CONFIG_ARM_SMP_TWD
-static struct clock_event_device __percpu *twd_clock_event;
-static int twd_ppi;
-
-static void __cpuinit twd_setup(struct clock_event_device *clk)
-{
-	clk->cpumask = cpumask_of(smp_processor_id());
-	clk->irq = twd_ppi;
-	twd_timer_setup(clk);
-}
-
 static void __cpuinit twd_teardown(void *data)
 {
 	struct clock_event_device *clk = data;
@@ -218,7 +183,7 @@ static int __cpuinit twd_cpu_notify(struct notifier_block *self,
 	switch (action) {
 	case CPU_STARTING:
 	case CPU_STARTING_FROZEN:
-		twd_setup(clk);
+		twd_timer_setup(clk);
 		break;
 
 	case CPU_DOWN_PREPARE:
@@ -250,9 +215,16 @@ static int __init twd_timer_common_init(void)
 		goto out_free;
 	}
 
+	err = request_percpu_irq(twd_ppi, twd_handler, "twd", twd_clock_event);
+	if (err) {
+		pr_err("twd: can't register interrupt %d (%d)\n",
+		       twd_ppi, err);
+		goto out_free;
+	}
+
 	/* Immediately configure the timer on the boot CPU */
 	clk = per_cpu_ptr(twd_clock_event, smp_processor_id());
-	twd_setup(clk);
+	twd_timer_setup(clk);
 
 	register_cpu_notifier(&twd_cpu_nb);
 
@@ -302,4 +274,3 @@ int __init twd_timer_of_init(const struct of_device_id *twd_of_match)
 	return twd_timer_common_init();
 }
 #endif
-#endif
-- 
1.7.7.1

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

* [PATCH v2 13/15] ARM: local timers: make MCT timer standalone
  2011-12-22 17:27 [PATCH v2 00/15] Make SMP timers standalone Marc Zyngier
                   ` (11 preceding siblings ...)
  2011-12-22 17:27 ` [PATCH v2 12/15] ARM: smp_twd: remove support for non-standalone version Marc Zyngier
@ 2011-12-22 17:27 ` Marc Zyngier
  2011-12-22 17:27 ` [PATCH v2 14/15] ARM: local timers: make MSM timers standalone Marc Zyngier
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Marc Zyngier @ 2011-12-22 17:27 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Cc: Kukjin Kim <kgene.kim@samsung.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/Kconfig           |    2 +-
 arch/arm/mach-exynos/mct.c |   85 ++++++++++++++++++++++++++++++-------------
 2 files changed, 60 insertions(+), 27 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c3732bb..f5563c5 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -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
diff --git a/arch/arm/mach-exynos/mct.c b/arch/arm/mach-exynos/mct.c
index 85b5527..2f1ab9f 100644
--- a/arch/arm/mach-exynos/mct.c
+++ b/arch/arm/mach-exynos/mct.c
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/percpu.h>
+#include <linux/cpu.h>
 
 #include <asm/hardware/gic.h>
 
@@ -39,7 +40,7 @@ static unsigned long clk_rate;
 static unsigned int mct_int_type;
 
 struct mct_clock_event_device {
-	struct clock_event_device *evt;
+	struct clock_event_device evt;
 	void __iomem *base;
 	char name[10];
 };
@@ -261,9 +262,7 @@ static void exynos4_clockevent_init(void)
 	setup_irq(IRQ_MCT_G0, &mct_comp_event_irq);
 }
 
-#ifdef CONFIG_LOCAL_TIMERS
-
-static DEFINE_PER_CPU(struct mct_clock_event_device, percpu_mct_tick);
+static struct mct_clock_event_device __percpu *mct_tick;
 
 /* Clock event handling */
 static void exynos4_mct_tick_stop(struct mct_clock_event_device *mevt)
@@ -303,8 +302,9 @@ static void exynos4_mct_tick_start(unsigned long cycles,
 static int exynos4_tick_set_next_event(unsigned long cycles,
 				       struct clock_event_device *evt)
 {
-	struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
+	struct mct_clock_event_device *mevt;
 
+	mevt = container_of(evt, struct mct_clock_event_device, evt);
 	exynos4_mct_tick_start(cycles, mevt);
 
 	return 0;
@@ -313,8 +313,9 @@ static int exynos4_tick_set_next_event(unsigned long cycles,
 static inline void exynos4_tick_set_mode(enum clock_event_mode mode,
 					 struct clock_event_device *evt)
 {
-	struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
+	struct mct_clock_event_device *mevt;
 
+	mevt = container_of(evt, struct mct_clock_event_device, evt);
 	exynos4_mct_tick_stop(mevt);
 
 	switch (mode) {
@@ -332,7 +333,7 @@ static inline void exynos4_tick_set_mode(enum clock_event_mode mode,
 
 static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
 {
-	struct clock_event_device *evt = mevt->evt;
+	struct clock_event_device *evt = &mevt->evt;
 
 	/*
 	 * This is for supporting oneshot mode.
@@ -354,7 +355,7 @@ static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
 static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)
 {
 	struct mct_clock_event_device *mevt = dev_id;
-	struct clock_event_device *evt = mevt->evt;
+	struct clock_event_device *evt = &mevt->evt;
 
 	exynos4_mct_tick_clear(mevt);
 
@@ -375,14 +376,11 @@ static struct irqaction mct_tick1_event_irq = {
 	.handler	= exynos4_mct_tick_isr,
 };
 
-static void exynos4_mct_tick_init(struct clock_event_device *evt)
+static void __cpuinit exynos4_mct_tick_init(struct mct_clock_event_device *mevt)
 {
-	struct mct_clock_event_device *mevt;
+	struct clock_event_device *evt = &mevt->evt;
 	unsigned int cpu = smp_processor_id();
 
-	mevt = this_cpu_ptr(&percpu_mct_tick);
-	mevt->evt = evt;
-
 	mevt->base = EXYNOS4_MCT_L_BASE(cpu);
 	sprintf(mevt->name, "mct_tick%d", cpu);
 
@@ -419,17 +417,12 @@ static void exynos4_mct_tick_init(struct clock_event_device *evt)
 	}
 }
 
-/* Setup the local clock events for a CPU */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-	exynos4_mct_tick_init(evt);
-
-	return 0;
-}
-
-void local_timer_stop(struct clock_event_device *evt)
+void exynos4_mct_tick_halt(void *data)
 {
+	struct mct_clock_event_device *mevt = data;
+	struct clock_event_device *evt = &mevt->evt;
 	unsigned int cpu = smp_processor_id();
+
 	evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
 	if (mct_int_type == MCT_INT_SPI)
 		if (cpu == 0)
@@ -439,7 +432,48 @@ void local_timer_stop(struct clock_event_device *evt)
 	else
 		disable_percpu_irq(IRQ_MCT_LOCALTIMER);
 }
-#endif /* CONFIG_LOCAL_TIMERS */
+
+static int __cpuinit exynos4_mct_cpu_notify(struct notifier_block *self,
+					    unsigned long action, void *data)
+{
+	int cpu = (int)data;
+	struct mct_clock_event_device *mevt = per_cpu_ptr(mct_tick, cpu);
+
+	switch (action) {
+	case CPU_STARTING:
+	case CPU_STARTING_FROZEN:
+		exynos4_mct_tick_init(mevt);
+		break;
+
+	case CPU_DOWN_PREPARE:
+	case CPU_DOWN_PREPARE_FROZEN:
+		smp_call_function_single(cpu, exynos4_mct_tick_halt, mevt, 1);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata exynos4_mct_cpu_nb = {
+	.notifier_call = exynos4_mct_cpu_notify,
+};
+
+static void __init exynos4_mct_init(void)
+{
+	struct mct_clock_event_device *mevt;
+
+	mct_tick = alloc_percpu(struct mct_clock_event_device);
+	if (!mct_tick) {
+		pr_err("exynos4_mct_init: can't allocate memory\n");
+		return;
+	}
+
+	/* Immediately configure the timer on the boot CPU */
+	mevt = per_cpu_ptr(mct_tick, smp_processor_id());
+	exynos4_mct_tick_init(mevt);
+
+	register_cpu_notifier(&exynos4_mct_cpu_nb);
+}
 
 static void __init exynos4_timer_resources(void)
 {
@@ -448,17 +482,15 @@ static void __init exynos4_timer_resources(void)
 
 	clk_rate = clk_get_rate(mct_clk);
 
-#ifdef CONFIG_LOCAL_TIMERS
 	if (mct_int_type == MCT_INT_PPI) {
 		int err;
 
 		err = request_percpu_irq(IRQ_MCT_LOCALTIMER,
 					 exynos4_mct_tick_isr, "MCT",
-					 &percpu_mct_tick);
+					 mct_tick);
 		WARN(err, "MCT: can't request IRQ %d (%d)\n",
 		     IRQ_MCT_LOCALTIMER, err);
 	}
-#endif /* CONFIG_LOCAL_TIMERS */
 }
 
 static void __init exynos4_timer_init(void)
@@ -471,6 +503,7 @@ static void __init exynos4_timer_init(void)
 	exynos4_timer_resources();
 	exynos4_clocksource_init();
 	exynos4_clockevent_init();
+	exynos4_mct_init();
 }
 
 struct sys_timer exynos4_timer = {
-- 
1.7.7.1

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

* [PATCH v2 14/15] ARM: local timers: make MSM timers standalone
  2011-12-22 17:27 [PATCH v2 00/15] Make SMP timers standalone Marc Zyngier
                   ` (12 preceding siblings ...)
  2011-12-22 17:27 ` [PATCH v2 13/15] ARM: local timers: make MCT timer standalone Marc Zyngier
@ 2011-12-22 17:27 ` Marc Zyngier
  2011-12-22 17:27 ` [PATCH v2 15/15] ARM: local timers: Remove CONFIG_LOCAL_TIMERS support Marc Zyngier
  2011-12-22 19:32 ` [PATCH v2 00/15] Make SMP timers standalone Russell King - ARM Linux
  15 siblings, 0 replies; 40+ messages in thread
From: Marc Zyngier @ 2011-12-22 17:27 UTC (permalink / raw)
  To: linux-arm-kernel

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 <davidb@codeaurora.org>
Cc: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/Kconfig          |    2 +-
 arch/arm/mach-msm/timer.c |   92 +++++++++++++++++++++++++++++++++-----------
 2 files changed, 70 insertions(+), 24 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index f5563c5..cea5e72 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -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
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 11d0d8f..ac055c9 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -20,10 +20,11 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/io.h>
+#include <linux/cpu.h>
+#include <linux/slab.h>
 
 #include <asm/mach/time.h>
 #include <asm/hardware/gic.h>
-#include <asm/localtimer.h>
 
 #include <mach/msm_iomap.h>
 #include <mach/cpu.h>
@@ -46,7 +47,7 @@ static void __iomem *event_base;
 
 static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
 {
-	struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
+	struct clock_event_device *evt = dev_id;
 	/* Stop the timer tick */
 	if (evt->mode == CLOCK_EVT_MODE_ONESHOT) {
 		u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE);
@@ -100,7 +101,7 @@ static struct clock_event_device msm_clockevent = {
 
 static union {
 	struct clock_event_device *evt;
-	struct clock_event_device __percpu **percpu_evt;
+	struct clock_event_device __percpu *percpu_evt;
 } msm_evt;
 
 static void __iomem *source_base;
@@ -127,7 +128,7 @@ static struct clocksource msm_clocksource = {
 	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-static void __init msm_timer_init(void)
+static void __init msm_timer_primary_setup(void)
 {
 	struct clock_event_device *ce = &msm_clockevent;
 	struct clocksource *cs = &msm_clocksource;
@@ -154,6 +155,13 @@ static void __init msm_timer_init(void)
 		source_base = MSM_TMR0_BASE + 0x24;
 		dgt_hz = 27000000 / 4;
 		writel_relaxed(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
+		msm_evt.percpu_evt = alloc_percpu(struct clock_event_device);
+		if (!msm_evt.percpu_evt) {
+			pr_err("memory allocation failed for %s\n", ce->name);
+			goto err;
+		}
+		ce = __this_cpu_ptr(msm_evt.percpu_evt);
+		*ce = msm_clockevent; /* Use msm_clockevent as a template */
 	} else
 		BUG();
 
@@ -165,12 +173,8 @@ static void __init msm_timer_init(void)
 	ce->irq = INT_GP_TIMER_EXP;
 	clockevents_config_and_register(ce, GPT_HZ, 4, 0xffffffff);
 	if (cpu_is_msm8x60() || cpu_is_msm8960()) {
-		msm_evt.percpu_evt = alloc_percpu(struct clock_event_device *);
-		if (!msm_evt.percpu_evt) {
-			pr_err("memory allocation failed for %s\n", ce->name);
-			goto err;
-		}
-		*__this_cpu_ptr(msm_evt.percpu_evt) = ce;
+		msm_clockevent.irq = ce->irq;
+		msm_clockevent.shift = ce->shift;
 		res = request_percpu_irq(ce->irq, msm_timer_interrupt,
 					 ce->name, msm_evt.percpu_evt);
 		if (!res)
@@ -179,7 +183,7 @@ static void __init msm_timer_init(void)
 		msm_evt.evt = ce;
 		res = request_irq(ce->irq, msm_timer_interrupt,
 				  IRQF_TIMER | IRQF_NOBALANCING |
-				  IRQF_TRIGGER_RISING, ce->name, &msm_evt.evt);
+				  IRQF_TRIGGER_RISING, ce->name, msm_evt.evt);
 	}
 
 	if (res)
@@ -191,16 +195,18 @@ err:
 		pr_err("clocksource_register failed\n");
 }
 
-#ifdef CONFIG_LOCAL_TIMERS
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
+#ifdef CONFIG_SMP
+static void __cpuinit msm_timer_secondary_setup(struct clock_event_device *evt)
 {
-	/* Use existing clock_event for cpu 0 */
-	if (!smp_processor_id())
-		return 0;
+	static bool local_timer_inited;
+
+	if (!local_timer_inited) {
+		writel_relaxed(0, event_base + TIMER_ENABLE);
+		writel_relaxed(0, event_base + TIMER_CLEAR);
+		writel_relaxed(~0, event_base + TIMER_MATCH_VAL);
+		local_timer_inited = true;
+	}
 
-	writel_relaxed(0, event_base + TIMER_ENABLE);
-	writel_relaxed(0, event_base + TIMER_CLEAR);
-	writel_relaxed(~0, event_base + TIMER_MATCH_VAL);
 	evt->irq = msm_clockevent.irq;
 	evt->name = "local_timer";
 	evt->features = msm_clockevent.features;
@@ -211,19 +217,59 @@ int __cpuinit local_timer_setup(struct clock_event_device *evt)
 	evt->mult = div_sc(GPT_HZ, NSEC_PER_SEC, evt->shift);
 	evt->max_delta_ns = clockevent_delta2ns(0xf0000000, evt);
 	evt->min_delta_ns = clockevent_delta2ns(4, evt);
+	evt->cpumask = cpumask_of(smp_processor_id());
 
-	*__this_cpu_ptr(msm_evt.percpu_evt) = evt;
 	clockevents_register_device(evt);
+
 	enable_percpu_irq(evt->irq, 0);
-	return 0;
 }
 
-void local_timer_stop(struct clock_event_device *evt)
+void msm_timer_secondary_teardown(void *data)
 {
+	struct clock_event_device *evt = data;
 	evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
 	disable_percpu_irq(evt->irq);
 }
-#endif /* CONFIG_LOCAL_TIMERS */
+
+static int __cpuinit msm_timer_cpu_notify(struct notifier_block *self,
+					  unsigned long action, void *data)
+{
+	int cpu = (int)data;
+	struct clock_event_device *clk;
+
+	clk = per_cpu_ptr(msm_evt.percpu_evt, cpu);
+
+	switch (action) {
+	case CPU_STARTING:
+	case CPU_STARTING_FROZEN:
+		msm_timer_secondary_setup(clk);
+		break;
+
+	case CPU_DOWN_PREPARE:
+	case CPU_DOWN_PREPARE_FROZEN:
+		smp_call_function_single(cpu, msm_timer_secondary_teardown,
+					 clk, 1);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata msm_timer_cpu_nb = {
+	.notifier_call = msm_timer_cpu_notify,
+};
+#endif
+
+static void __init msm_timer_init(void)
+{
+	/* Immediately configure the timer on the boot CPU */
+	msm_timer_primary_setup();
+
+#ifdef CONFIG_SMP
+	if (cpu_is_msm8x60() || cpu_is_msm8960())
+		register_cpu_notifier(&msm_timer_cpu_nb);
+#endif
+}
 
 struct sys_timer msm_timer = {
 	.init = msm_timer_init
-- 
1.7.7.1

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

* [PATCH v2 15/15] ARM: local timers: Remove CONFIG_LOCAL_TIMERS support
  2011-12-22 17:27 [PATCH v2 00/15] Make SMP timers standalone Marc Zyngier
                   ` (13 preceding siblings ...)
  2011-12-22 17:27 ` [PATCH v2 14/15] ARM: local timers: make MSM timers standalone Marc Zyngier
@ 2011-12-22 17:27 ` Marc Zyngier
  2011-12-22 19:32 ` [PATCH v2 00/15] Make SMP timers standalone Russell King - ARM Linux
  15 siblings, 0 replies; 40+ messages in thread
From: Marc Zyngier @ 2011-12-22 17:27 UTC (permalink / raw)
  To: linux-arm-kernel

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

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 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

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index cea5e72..46ce570 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -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
diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h
deleted file mode 100644
index 5f21c37..0000000
--- a/arch/arm/include/asm/localtimer.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- *  arch/arm/include/asm/localtimer.h
- *
- *  Copyright (C) 2004-2005 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.
- */
-#ifndef __ASM_ARM_LOCALTIMER_H
-#define __ASM_ARM_LOCALTIMER_H
-
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-
-struct clock_event_device;
-
-/*
- * Setup a per-cpu timer, whether it be a local timer or dummy broadcast
- */
-void percpu_timer_setup(void);
-
-#ifdef CONFIG_LOCAL_TIMERS
-
-/*
- * Stop the local timer
- */
-void local_timer_stop(struct clock_event_device *);
-
-/*
- * Setup a local timer interrupt for a CPU.
- */
-int local_timer_setup(struct clock_event_device *);
-
-#else
-
-static inline int local_timer_setup(struct clock_event_device *evt)
-{
-	return -ENXIO;
-}
-
-static inline void local_timer_stop(struct clock_event_device *evt)
-{
-}
-#endif
-
-#endif
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 57db122..123b30d 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -40,7 +40,6 @@
 #include <asm/sections.h>
 #include <asm/tlbflush.h>
 #include <asm/ptrace.h>
-#include <asm/localtimer.h>
 #include <asm/smp_plat.h>
 
 /*
@@ -128,8 +127,6 @@ int __cpuinit __cpu_up(unsigned int cpu)
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-static void percpu_timer_stop(void);
-
 /*
  * __cpu_disable runs on the processor to be shutdown.
  */
@@ -155,11 +152,6 @@ int __cpu_disable(void)
 	migrate_irqs();
 
 	/*
-	 * Stop the local timer for this CPU.
-	 */
-	percpu_timer_stop();
-
-	/*
 	 * Flush user cache and TLB mappings, and then remove this CPU
 	 * from the vm mask set of all processes.
 	 */
@@ -260,6 +252,8 @@ static void __cpuinit smp_store_cpu_info(unsigned int cpuid)
 	store_cpu_topology(cpuid);
 }
 
+static void broadcast_timer_setup(void);
+
 /*
  * This is the secondary CPU boot entry.  We're using this CPUs
  * idle thread stack, but a set of temporary page tables.
@@ -307,7 +301,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
 	/*
 	 * Setup the percpu timer for this CPU.
 	 */
-	percpu_timer_setup();
+	broadcast_timer_setup();
 
 	while (!cpu_active(cpu))
 		cpu_relax();
@@ -362,10 +356,10 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
 		max_cpus = ncores;
 	if (ncores > 1 && max_cpus) {
 		/*
-		 * Enable the local timer or broadcast device for the
-		 * boot CPU, but only if we have more than one CPU.
+		 * Enable the broadcast device for the boot CPU, but
+		 * only if we have more than one CPU.
 		 */
-		percpu_timer_setup();
+		broadcast_timer_setup();
 
 		/*
 		 * Initialise the present map, which describes the set of CPUs
@@ -436,7 +430,7 @@ u64 smp_irq_stat_cpu(unsigned int cpu)
 }
 
 /*
- * Timer (local or broadcast) support
+ * Broadcast timer support
  */
 static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent);
 
@@ -462,8 +456,11 @@ static void broadcast_timer_set_mode(enum clock_event_mode mode,
 {
 }
 
-static void __cpuinit broadcast_timer_setup(struct clock_event_device *evt)
+static void __cpuinit broadcast_timer_setup(void)
 {
+	unsigned int cpu = smp_processor_id();
+	struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
+
 	evt->name	= "dummy_timer";
 	evt->features	= CLOCK_EVT_FEAT_ONESHOT |
 			  CLOCK_EVT_FEAT_PERIODIC |
@@ -471,37 +468,12 @@ static void __cpuinit broadcast_timer_setup(struct clock_event_device *evt)
 	evt->rating	= 400;
 	evt->mult	= 1;
 	evt->set_mode	= broadcast_timer_set_mode;
+	evt->cpumask	= cpumask_of(cpu);
+	evt->broadcast	= smp_timer_broadcast;
 
 	clockevents_register_device(evt);
 }
 
-void __cpuinit percpu_timer_setup(void)
-{
-	unsigned int cpu = smp_processor_id();
-	struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
-
-	evt->cpumask = cpumask_of(cpu);
-	evt->broadcast = smp_timer_broadcast;
-
-	if (local_timer_setup(evt))
-		broadcast_timer_setup(evt);
-}
-
-#ifdef CONFIG_HOTPLUG_CPU
-/*
- * The generic clock events code purposely does not stop the local timer
- * on CPU_DEAD/CPU_DEAD_FROZEN hotplug events, so we have to do it
- * manually here.
- */
-static void percpu_timer_stop(void)
-{
-	unsigned int cpu = smp_processor_id();
-	struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
-
-	local_timer_stop(evt);
-}
-#endif
-
 static DEFINE_RAW_SPINLOCK(stop_lock);
 
 /*
-- 
1.7.7.1

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

* [PATCH v2 06/15] ARM: local timers: switch tegra to standalone smp_twd
  2011-12-22 17:27 ` [PATCH v2 06/15] ARM: local timers: switch tegra to standalone smp_twd Marc Zyngier
@ 2011-12-22 19:22   ` Colin Cross
  0 siblings, 0 replies; 40+ messages in thread
From: Colin Cross @ 2011-12-22 19:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Dec 22, 2011 at 9:27 AM, Marc Zyngier <marc.zyngier@arm.com> wrote:
> 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 <ccross@android.com>
> Cc: Erik Gilling <konkers@android.com>
> Cc: Olof Johansson <olof@lixom.net>
> Cc: Stephen Warren <swarren@nvidia.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Acked-by: Colin Cross <ccross@android.com>

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

* [PATCH v2 00/15] Make SMP timers standalone
  2011-12-22 17:27 [PATCH v2 00/15] Make SMP timers standalone Marc Zyngier
                   ` (14 preceding siblings ...)
  2011-12-22 17:27 ` [PATCH v2 15/15] ARM: local timers: Remove CONFIG_LOCAL_TIMERS support Marc Zyngier
@ 2011-12-22 19:32 ` Russell King - ARM Linux
  2012-01-04 17:39   ` Marc Zyngier
  15 siblings, 1 reply; 40+ messages in thread
From: Russell King - ARM Linux @ 2011-12-22 19:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Dec 22, 2011 at 05:27:30PM +0000, Marc Zyngier wrote:
> 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.

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

* [PATCH v2 01/15] ARM: local timers: allow smp_twd to be used standalone
  2011-12-22 17:27 ` [PATCH v2 01/15] ARM: local timers: allow smp_twd to be used standalone Marc Zyngier
@ 2011-12-22 20:38   ` Russell King - ARM Linux
  0 siblings, 0 replies; 40+ messages in thread
From: Russell King - ARM Linux @ 2011-12-22 20:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Dec 22, 2011 at 05:27:31PM +0000, Marc Zyngier wrote:
> +	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.

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

* [PATCH v2 07/15] ARM: local timers: switch omap4 to standalone smp_twd
  2011-12-22 17:27 ` [PATCH v2 07/15] ARM: local timers: switch omap4 " Marc Zyngier
@ 2011-12-23  6:37   ` Shilimkar, Santosh
  0 siblings, 0 replies; 40+ messages in thread
From: Shilimkar, Santosh @ 2011-12-23  6:37 UTC (permalink / raw)
  To: linux-arm-kernel

Marc,
On Thu, Dec 22, 2011 at 10:57 PM, Marc Zyngier <marc.zyngier@arm.com> wrote:
> 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.
>
> Cc: Tony Lindgren <tony@atomide.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

IIRC, have reviewed this earlier. Looking at the patch the changes are almost
same. So for OMAP changes
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>

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

* [PATCH v2 11/15] ARM: local timers: switch imx6q to standalone smp_twd
  2011-12-22 17:27 ` [PATCH v2 11/15] ARM: local timers: switch imx6q " Marc Zyngier
@ 2011-12-25 13:40   ` Shawn Guo
  0 siblings, 0 replies; 40+ messages in thread
From: Shawn Guo @ 2011-12-25 13:40 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Marc,

On Thu, Dec 22, 2011 at 05:27:41PM +0000, Marc Zyngier wrote:
> 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.
> 
> Cc: Shawn Guo <shawn.guo@linaro.org>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  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,

Tested-by: Shawn Guo <shawn.guo@linaro.org>

-- 
Regards,
Shawn

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

* [PATCH v2 00/15] Make SMP timers standalone
  2011-12-22 19:32 ` [PATCH v2 00/15] Make SMP timers standalone Russell King - ARM Linux
@ 2012-01-04 17:39   ` Marc Zyngier
  2012-01-04 21:47     ` Russell King - ARM Linux
  2012-01-05  1:17     ` David Brown
  0 siblings, 2 replies; 40+ messages in thread
From: Marc Zyngier @ 2012-01-04 17:39 UTC (permalink / raw)
  To: linux-arm-kernel

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

Hi Russell,

> On Thu, Dec 22, 2011 at 05:27:30PM +0000, Marc Zyngier wrote:
>> 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).

> 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.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v2 00/15] Make SMP timers standalone
  2012-01-04 17:39   ` Marc Zyngier
@ 2012-01-04 21:47     ` Russell King - ARM Linux
  2012-01-05  0:00       ` Linus Walleij
  2012-01-05 10:33       ` Marc Zyngier
  2012-01-05  1:17     ` David Brown
  1 sibling, 2 replies; 40+ messages in thread
From: Russell King - ARM Linux @ 2012-01-04 21:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jan 04, 2012 at 05:39:16PM +0000, Marc Zyngier wrote:
> On 22/12/11 19:32, Russell King - ARM Linux wrote:
> > 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.

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

* [PATCH v2 00/15] Make SMP timers standalone
  2012-01-04 21:47     ` Russell King - ARM Linux
@ 2012-01-05  0:00       ` Linus Walleij
  2012-01-05 11:08         ` Marc Zyngier
  2012-01-05 10:33       ` Marc Zyngier
  1 sibling, 1 reply; 40+ messages in thread
From: Linus Walleij @ 2012-01-05  0:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jan 4, 2012 at 10:47 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Wed, Jan 04, 2012 at 05:39:16PM +0000, Marc Zyngier wrote:
>> On 22/12/11 19:32, Russell King - ARM Linux wrote:
>> > 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.

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

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

* [PATCH v2 00/15] Make SMP timers standalone
  2012-01-04 17:39   ` Marc Zyngier
  2012-01-04 21:47     ` Russell King - ARM Linux
@ 2012-01-05  1:17     ` David Brown
  2012-01-05 10:26       ` Linus Walleij
  1 sibling, 1 reply; 40+ messages in thread
From: David Brown @ 2012-01-05  1:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jan 04, 2012 at 05:39:16PM +0000, Marc Zyngier wrote:
> On 22/12/11 19:32, Russell King - ARM Linux wrote:
> 
> Hi Russell,
> 
> > On Thu, Dec 22, 2011 at 05:27:30PM +0000, Marc Zyngier wrote:
> >> 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).

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

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

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

* [PATCH v2 00/15] Make SMP timers standalone
  2012-01-05  1:17     ` David Brown
@ 2012-01-05 10:26       ` Linus Walleij
  2012-01-05 11:01         ` Russell King - ARM Linux
  2012-01-05 19:34         ` johlstei
  0 siblings, 2 replies; 40+ messages in thread
From: Linus Walleij @ 2012-01-05 10:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 5, 2012 at 2:17 AM, David Brown <davidb@codeaurora.org> wrote:
> On Wed, Jan 04, 2012 at 05:39:16PM +0000, Marc Zyngier wrote:
>> 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?

> 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

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

* [PATCH v2 00/15] Make SMP timers standalone
  2012-01-04 21:47     ` Russell King - ARM Linux
  2012-01-05  0:00       ` Linus Walleij
@ 2012-01-05 10:33       ` Marc Zyngier
  2012-01-05 10:45         ` Shilimkar, Santosh
  1 sibling, 1 reply; 40+ messages in thread
From: Marc Zyngier @ 2012-01-05 10:33 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/01/12 21:47, Russell King - ARM Linux wrote:
> On Wed, Jan 04, 2012 at 05:39:16PM +0000, Marc Zyngier wrote:
>> On 22/12/11 19:32, Russell King - ARM Linux wrote:
>>> 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.

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.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v2 00/15] Make SMP timers standalone
  2012-01-05 10:33       ` Marc Zyngier
@ 2012-01-05 10:45         ` Shilimkar, Santosh
  0 siblings, 0 replies; 40+ messages in thread
From: Shilimkar, Santosh @ 2012-01-05 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 5, 2012 at 11:33 AM, Marc Zyngier <marc.zyngier@arm.com> wrote:
> On 04/01/12 21:47, Russell King - ARM Linux wrote:
>> On Wed, Jan 04, 2012 at 05:39:16PM +0000, Marc Zyngier wrote:
>>> On 22/12/11 19:32, Russell King - ARM Linux wrote:
>>>> 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.
>
> 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

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

* [PATCH v2 00/15] Make SMP timers standalone
  2012-01-05 10:26       ` Linus Walleij
@ 2012-01-05 11:01         ` Russell King - ARM Linux
  2012-01-05 19:34         ` johlstei
  1 sibling, 0 replies; 40+ messages in thread
From: Russell King - ARM Linux @ 2012-01-05 11:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 05, 2012 at 11:26:12AM +0100, Linus Walleij wrote:
> 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.

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

* [PATCH v2 00/15] Make SMP timers standalone
  2012-01-05  0:00       ` Linus Walleij
@ 2012-01-05 11:08         ` Marc Zyngier
  2012-01-05 11:13           ` Shilimkar, Santosh
  0 siblings, 1 reply; 40+ messages in thread
From: Marc Zyngier @ 2012-01-05 11:08 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/01/12 00:00, Linus Walleij wrote:
> 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?

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

> 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.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v2 00/15] Make SMP timers standalone
  2012-01-05 11:08         ` Marc Zyngier
@ 2012-01-05 11:13           ` Shilimkar, Santosh
  2012-01-05 11:19             ` Marc Zyngier
  0 siblings, 1 reply; 40+ messages in thread
From: Shilimkar, Santosh @ 2012-01-05 11:13 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 5, 2012 at 12:08 PM, Marc Zyngier <marc.zyngier@arm.com> wrote:
> On 05/01/12 00:00, Linus Walleij wrote:
>> 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?
>
> Yes. You get about 8 ticks worth of SP804, and then switch to TWD for good.
>
>> 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).
>
That's only because CPUIDLE low power states are not enabled. You
do that and without global timer, system will just die

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

* [PATCH v2 00/15] Make SMP timers standalone
  2012-01-05 11:13           ` Shilimkar, Santosh
@ 2012-01-05 11:19             ` Marc Zyngier
  2012-01-05 11:26               ` Russell King - ARM Linux
  2012-01-05 11:31               ` Shilimkar, Santosh
  0 siblings, 2 replies; 40+ messages in thread
From: Marc Zyngier @ 2012-01-05 11:19 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/01/12 11:13, Shilimkar, Santosh wrote:
> On Thu, Jan 5, 2012 at 12:08 PM, Marc Zyngier <marc.zyngier@arm.com> wrote:
>> On 05/01/12 00:00, Linus Walleij wrote:
>>> 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?
>>
>> Yes. You get about 8 ticks worth of SP804, and then switch to TWD for good.
>>
>>> 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).
>>
> 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.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v2 00/15] Make SMP timers standalone
  2012-01-05 11:19             ` Marc Zyngier
@ 2012-01-05 11:26               ` Russell King - ARM Linux
  2012-01-05 11:35                 ` Marc Zyngier
  2012-01-05 11:31               ` Shilimkar, Santosh
  1 sibling, 1 reply; 40+ messages in thread
From: Russell King - ARM Linux @ 2012-01-05 11:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 05, 2012 at 11:19:32AM +0000, Marc Zyngier wrote:
> 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.

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

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

* [PATCH v2 00/15] Make SMP timers standalone
  2012-01-05 11:19             ` Marc Zyngier
  2012-01-05 11:26               ` Russell King - ARM Linux
@ 2012-01-05 11:31               ` Shilimkar, Santosh
  1 sibling, 0 replies; 40+ messages in thread
From: Shilimkar, Santosh @ 2012-01-05 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 5, 2012 at 12:19 PM, Marc Zyngier <marc.zyngier@arm.com> wrote:
> On 05/01/12 11:13, Shilimkar, Santosh wrote:
>> On Thu, Jan 5, 2012 at 12:08 PM, Marc Zyngier <marc.zyngier@arm.com> wrote:
>>> On 05/01/12 00:00, Linus Walleij wrote:
>>>> 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?
>>>
>>> Yes. You get about 8 ticks worth of SP804, and then switch to TWD for good.
>>>
>>>> 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).
>>>
>> 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.
>
Great. Thanks for clarifying Marc.

Regards
Santosh

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

* [PATCH v2 00/15] Make SMP timers standalone
  2012-01-05 11:26               ` Russell King - ARM Linux
@ 2012-01-05 11:35                 ` Marc Zyngier
  2012-01-05 12:10                   ` Russell King - ARM Linux
  0 siblings, 1 reply; 40+ messages in thread
From: Marc Zyngier @ 2012-01-05 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/01/12 11:26, Russell King - ARM Linux wrote:
> On Thu, Jan 05, 2012 at 11:19:32AM +0000, Marc Zyngier wrote:
>> 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.
> 
>> 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).

> 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.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v2 00/15] Make SMP timers standalone
  2012-01-05 11:35                 ` Marc Zyngier
@ 2012-01-05 12:10                   ` Russell King - ARM Linux
  2012-01-05 16:13                     ` Marc Zyngier
  0 siblings, 1 reply; 40+ messages in thread
From: Russell King - ARM Linux @ 2012-01-05 12:10 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 05, 2012 at 11:35:56AM +0000, Marc Zyngier wrote:
> On 05/01/12 11:26, Russell King - ARM Linux wrote:
> > 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.

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

* [PATCH v2 00/15] Make SMP timers standalone
  2012-01-05 12:10                   ` Russell King - ARM Linux
@ 2012-01-05 16:13                     ` Marc Zyngier
  2012-01-05 16:26                       ` Russell King - ARM Linux
  0 siblings, 1 reply; 40+ messages in thread
From: Marc Zyngier @ 2012-01-05 16:13 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/01/12 12:10, Russell King - ARM Linux wrote:
> On Thu, Jan 05, 2012 at 11:35:56AM +0000, Marc Zyngier wrote:
>> On 05/01/12 11:26, Russell King - ARM Linux wrote:
>>> 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.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v2 00/15] Make SMP timers standalone
  2012-01-05 16:13                     ` Marc Zyngier
@ 2012-01-05 16:26                       ` Russell King - ARM Linux
  2012-01-05 16:55                         ` Russell King - ARM Linux
  0 siblings, 1 reply; 40+ messages in thread
From: Russell King - ARM Linux @ 2012-01-05 16:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 05, 2012 at 04:13:01PM +0000, Marc Zyngier wrote:
> On 05/01/12 12:10, Russell King - ARM Linux wrote:
> > On Thu, Jan 05, 2012 at 11:35:56AM +0000, Marc Zyngier wrote:
> >> On 05/01/12 11:26, Russell King - ARM Linux wrote:
> >>> 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.

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.

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

* [PATCH v2 00/15] Make SMP timers standalone
  2012-01-05 16:26                       ` Russell King - ARM Linux
@ 2012-01-05 16:55                         ` Russell King - ARM Linux
  0 siblings, 0 replies; 40+ messages in thread
From: Russell King - ARM Linux @ 2012-01-05 16:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 05, 2012 at 04:26:50PM +0000, Russell King - ARM Linux wrote:
> 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 <rmk+kernel@arm.linux.org.uk>
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.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 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(-)

diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h
index ef9ffba9..855f58e 100644
--- a/arch/arm/include/asm/smp_twd.h
+++ b/arch/arm/include/asm/smp_twd.h
@@ -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
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index c8e9385..f43f039 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -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;
+}
diff --git a/arch/arm/mach-highbank/localtimer.c b/arch/arm/mach-highbank/localtimer.c
index 5a00e79..1b6c0d1 100644
--- a/arch/arm/mach-highbank/localtimer.c
+++ b/arch/arm/mach-highbank/localtimer.c
@@ -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);
 }
diff --git a/arch/arm/mach-imx/localtimer.c b/arch/arm/mach-imx/localtimer.c
index 3a16351..1252c22 100644
--- a/arch/arm/mach-imx/localtimer.c
+++ b/arch/arm/mach-imx/localtimer.c
@@ -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);
 }

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

* [PATCH v2 00/15] Make SMP timers standalone
  2012-01-05 10:26       ` Linus Walleij
  2012-01-05 11:01         ` Russell King - ARM Linux
@ 2012-01-05 19:34         ` johlstei
  1 sibling, 0 replies; 40+ messages in thread
From: johlstei @ 2012-01-05 19:34 UTC (permalink / raw)
  To: linux-arm-kernel

On 01/05/2012 02:26 AM, Linus Walleij wrote:
> On Thu, Jan 5, 2012 at 2:17 AM, David Brown<davidb@codeaurora.org>  wrote:
>> On Wed, Jan 04, 2012 at 05:39:16PM +0000, Marc Zyngier wrote:
>>> 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

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

end of thread, other threads:[~2012-01-05 19:34 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-12-22 17:27 [PATCH v2 00/15] Make SMP timers standalone Marc Zyngier
2011-12-22 17:27 ` [PATCH v2 01/15] ARM: local timers: allow smp_twd to be used standalone Marc Zyngier
2011-12-22 20:38   ` Russell King - ARM Linux
2011-12-22 17:27 ` [PATCH v2 02/15] ARM: smp_twd: add device tree support Marc Zyngier
2011-12-22 17:27 ` [PATCH v2 03/15] ARM: local timers: switch realview to standalone smp_twd Marc Zyngier
2011-12-22 17:27 ` [PATCH v2 04/15] ARM: local timers: switch vexpress " Marc Zyngier
2011-12-22 17:27 ` [PATCH v2 05/15] ARM: local timers: remove localtimer.c from plat-versatile Marc Zyngier
2011-12-22 17:27 ` [PATCH v2 06/15] ARM: local timers: switch tegra to standalone smp_twd Marc Zyngier
2011-12-22 19:22   ` Colin Cross
2011-12-22 17:27 ` [PATCH v2 07/15] ARM: local timers: switch omap4 " Marc Zyngier
2011-12-23  6:37   ` Shilimkar, Santosh
2011-12-22 17:27 ` [PATCH v2 08/15] ARM: local timers: switch shmobile " Marc Zyngier
2011-12-22 17:27 ` [PATCH v2 09/15] ARM: local timers: switch ux500 " Marc Zyngier
2011-12-22 17:27 ` [PATCH v2 10/15] ARM: local timers: switch highbank " Marc Zyngier
2011-12-22 17:27 ` [PATCH v2 11/15] ARM: local timers: switch imx6q " Marc Zyngier
2011-12-25 13:40   ` Shawn Guo
2011-12-22 17:27 ` [PATCH v2 12/15] ARM: smp_twd: remove support for non-standalone version Marc Zyngier
2011-12-22 17:27 ` [PATCH v2 13/15] ARM: local timers: make MCT timer standalone Marc Zyngier
2011-12-22 17:27 ` [PATCH v2 14/15] ARM: local timers: make MSM timers standalone Marc Zyngier
2011-12-22 17:27 ` [PATCH v2 15/15] ARM: local timers: Remove CONFIG_LOCAL_TIMERS support Marc Zyngier
2011-12-22 19:32 ` [PATCH v2 00/15] Make SMP timers standalone Russell King - ARM Linux
2012-01-04 17:39   ` Marc Zyngier
2012-01-04 21:47     ` Russell King - ARM Linux
2012-01-05  0:00       ` Linus Walleij
2012-01-05 11:08         ` Marc Zyngier
2012-01-05 11:13           ` Shilimkar, Santosh
2012-01-05 11:19             ` Marc Zyngier
2012-01-05 11:26               ` Russell King - ARM Linux
2012-01-05 11:35                 ` Marc Zyngier
2012-01-05 12:10                   ` Russell King - ARM Linux
2012-01-05 16:13                     ` Marc Zyngier
2012-01-05 16:26                       ` Russell King - ARM Linux
2012-01-05 16:55                         ` Russell King - ARM Linux
2012-01-05 11:31               ` Shilimkar, Santosh
2012-01-05 10:33       ` Marc Zyngier
2012-01-05 10:45         ` Shilimkar, Santosh
2012-01-05  1:17     ` David Brown
2012-01-05 10:26       ` Linus Walleij
2012-01-05 11:01         ` Russell King - ARM Linux
2012-01-05 19:34         ` johlstei

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.