linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/8] Remove ARM local timer API
@ 2013-02-22  7:27 Stephen Boyd
  2013-02-22  7:27 ` [PATCH 1/8] ARM: smp: Lower rating of dummy broadcast device Stephen Boyd
                   ` (7 more replies)
  0 siblings, 8 replies; 19+ messages in thread
From: Stephen Boyd @ 2013-02-22  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

In light of Mark Rutland's recent work on divorcing the ARM architected
timers from the ARM local timer API and introducing a generic arch hook for
broadcast it seems that we should remove the local timer API entirely.
Doing so will reduce the architecture dependencies of our timer drivers,
reduce code in ARM core, and simplify timer drivers because they no longer
go through an architecture layer that is essentially a hotplug notifier.

Previous attempts have been made[1] unsuccessfully. I'm hoping this can
be accepted now so that we can clean up the timer drivers that are
used in both UP and SMP situations. Right now these drivers have to ignore
the timer setup callback on the boot CPU to avoid registering clockevents
twice. This is not very symmetric and causes convuluted code that does
the same thing in two places.

Patches based on linux-next-20130221. Mostly compile tested as I don't
have access to the hardware.

[1] http://article.gmane.org/gmane.linux.ports.arm.kernel/145705

Note: A hotplug notifier is used by both x86 for the apb_timer (see 
apbt_cpuhp_notify) and by metag (see arch_timer_cpu_notify in
metag_generic.c) so this is not new.

Stephen Boyd (8):
  ARM: smp: Lower rating of dummy broadcast device
  ARM: smp_twd: Divorce smp_twd from local timer API
  ARM: EXYNOS4: Divorce mct from local timer API
  ARM: PRIMA2: Divorce timer-marco from local timer API
  ARM: MSM: Divorce msm_timer from local timer API
  clocksource: time-armada-370-xp: Fix sparse warning
  clocksource: time-armada-370-xp: Divorce from local timer API
  ARM: smp: Remove local timer API

 arch/arm/Kconfig                         |  12 +--
 arch/arm/include/asm/localtimer.h        |  34 ---------
 arch/arm/kernel/smp.c                    |  69 +++--------------
 arch/arm/kernel/smp_twd.c                |  48 ++++++++----
 arch/arm/mach-exynos/mct.c               |  53 +++++++++----
 arch/arm/mach-msm/timer.c                | 125 +++++++++++++++++--------------
 arch/arm/mach-omap2/Kconfig              |   1 -
 arch/arm/mach-omap2/timer.c              |   7 --
 arch/arm/mach-prima2/timer-marco.c       |  98 ++++++++++++------------
 drivers/clocksource/time-armada-370-xp.c |  88 ++++++++++------------
 include/linux/time-armada-370-xp.h       |   4 +-
 11 files changed, 241 insertions(+), 298 deletions(-)
 delete mode 100644 arch/arm/include/asm/localtimer.h

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH 1/8] ARM: smp: Lower rating of dummy broadcast device
  2013-02-22  7:27 [PATCH 0/8] Remove ARM local timer API Stephen Boyd
@ 2013-02-22  7:27 ` Stephen Boyd
  2013-02-22  7:27 ` [PATCH 2/8] ARM: smp_twd: Divorce smp_twd from local timer API Stephen Boyd
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 19+ messages in thread
From: Stephen Boyd @ 2013-02-22  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

In the near future the dummy broadcast device will always be
registered with the clockevent core. If the rating of the dummy
is higher than the rating of the real clockevent the clockevents
core will try to replace the real clockevent with the dummy
broadcast. We don't want this to happen, so lower the rating to
something no good clockevent should choose.

Cc: Russell King <linux@arm.linux.org.uk>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
 arch/arm/kernel/smp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index fa86d1c..2d5197d 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -479,7 +479,7 @@ static void __cpuinit broadcast_timer_setup(struct clock_event_device *evt)
 	evt->features	= CLOCK_EVT_FEAT_ONESHOT |
 			  CLOCK_EVT_FEAT_PERIODIC |
 			  CLOCK_EVT_FEAT_DUMMY;
-	evt->rating	= 400;
+	evt->rating	= 100;
 	evt->mult	= 1;
 	evt->set_mode	= broadcast_timer_set_mode;
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH 2/8] ARM: smp_twd: Divorce smp_twd from local timer API
  2013-02-22  7:27 [PATCH 0/8] Remove ARM local timer API Stephen Boyd
  2013-02-22  7:27 ` [PATCH 1/8] ARM: smp: Lower rating of dummy broadcast device Stephen Boyd
@ 2013-02-22  7:27 ` Stephen Boyd
  2013-02-22  7:27 ` [PATCH 3/8] ARM: EXYNOS4: Divorce mct " Stephen Boyd
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 19+ messages in thread
From: Stephen Boyd @ 2013-02-22  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

Separate the smp_twd timers from the local timer API. This will
allow us to remove ARM local timer support in the near future and
gets us closer to moving this driver to drivers/clocksource.

Cc: Russell King <linux@arm.linux.org.uk>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
 arch/arm/kernel/smp_twd.c | 48 +++++++++++++++++++++++++++++++----------------
 1 file changed, 32 insertions(+), 16 deletions(-)

diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index c092115..2439843 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -11,6 +11,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/clk.h>
+#include <linux/cpu.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/err.h>
@@ -23,7 +24,6 @@
 #include <linux/of_address.h>
 
 #include <asm/smp_twd.h>
-#include <asm/localtimer.h>
 
 /* set up by the platform code */
 static void __iomem *twd_base;
@@ -32,7 +32,7 @@ static struct clk *twd_clk;
 static unsigned long twd_timer_rate;
 static DEFINE_PER_CPU(bool, percpu_setup_called);
 
-static struct clock_event_device __percpu **twd_evt;
+static struct clock_event_device __percpu *twd_evt;
 static int twd_ppi;
 
 static void twd_set_mode(enum clock_event_mode mode,
@@ -105,7 +105,7 @@ static void twd_update_frequency(void *new_rate)
 {
 	twd_timer_rate = *((unsigned long *) new_rate);
 
-	clockevents_update_freq(*__this_cpu_ptr(twd_evt), twd_timer_rate);
+	clockevents_update_freq(__this_cpu_ptr(twd_evt), twd_timer_rate);
 }
 
 static int twd_rate_change(struct notifier_block *nb,
@@ -131,7 +131,7 @@ static struct notifier_block twd_clk_nb = {
 
 static int twd_clk_init(void)
 {
-	if (twd_evt && *__this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk))
+	if (twd_evt && __this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk))
 		return clk_notifier_register(twd_clk, &twd_clk_nb);
 
 	return 0;
@@ -150,7 +150,7 @@ static void twd_update_frequency(void *data)
 {
 	twd_timer_rate = clk_get_rate(twd_clk);
 
-	clockevents_update_freq(*__this_cpu_ptr(twd_evt), twd_timer_rate);
+	clockevents_update_freq(__this_cpu_ptr(twd_evt), twd_timer_rate);
 }
 
 static int twd_cpufreq_transition(struct notifier_block *nb,
@@ -176,7 +176,7 @@ static struct notifier_block twd_cpufreq_nb = {
 
 static int twd_cpufreq_init(void)
 {
-	if (twd_evt && *__this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk))
+	if (twd_evt && __this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk))
 		return cpufreq_register_notifier(&twd_cpufreq_nb,
 			CPUFREQ_TRANSITION_NOTIFIER);
 
@@ -266,7 +266,6 @@ static void twd_get_clock(struct device_node *np)
  */
 static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 {
-	struct clock_event_device **this_cpu_clk;
 	int cpu = smp_processor_id();
 
 	/*
@@ -275,7 +274,7 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 	 */
 	if (per_cpu(percpu_setup_called, cpu)) {
 		__raw_writel(0, twd_base + TWD_TIMER_CONTROL);
-		clockevents_register_device(*__this_cpu_ptr(twd_evt));
+		clockevents_register_device(__this_cpu_ptr(twd_evt));
 		enable_percpu_irq(clk->irq, 0);
 		return 0;
 	}
@@ -296,9 +295,7 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 	clk->set_mode = twd_set_mode;
 	clk->set_next_event = twd_set_next_event;
 	clk->irq = twd_ppi;
-
-	this_cpu_clk = __this_cpu_ptr(twd_evt);
-	*this_cpu_clk = clk;
+	clk->cpumask = cpumask_of(cpu);
 
 	clockevents_config_and_register(clk, twd_timer_rate,
 					0xf, 0xffffffff);
@@ -307,16 +304,32 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 	return 0;
 }
 
-static struct local_timer_ops twd_lt_ops __cpuinitdata = {
-	.setup	= twd_timer_setup,
-	.stop	= twd_timer_stop,
+static int __cpuinit twd_timer_cpu_notify(struct notifier_block *self,
+					   unsigned long action, void *hcpu)
+{
+	struct clock_event_device *evt = this_cpu_ptr(twd_evt);
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_STARTING:
+		twd_timer_setup(evt);
+		break;
+	case CPU_DYING:
+		twd_timer_stop(evt);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block twd_timer_cpu_nb __cpuinitdata = {
+	.notifier_call = twd_timer_cpu_notify,
 };
 
 static int __init twd_local_timer_common_register(struct device_node *np)
 {
 	int err;
 
-	twd_evt = alloc_percpu(struct clock_event_device *);
+	twd_evt = alloc_percpu(struct clock_event_device);
 	if (!twd_evt) {
 		err = -ENOMEM;
 		goto out_free;
@@ -328,10 +341,13 @@ static int __init twd_local_timer_common_register(struct device_node *np)
 		goto out_free;
 	}
 
-	err = local_timer_register(&twd_lt_ops);
+	err = register_cpu_notifier(&twd_timer_cpu_nb);
 	if (err)
 		goto out_irq;
 
+	/* Immediately configure the timer on the boot CPU */
+	twd_timer_setup(this_cpu_ptr(twd_evt));
+
 	twd_get_clock(np);
 
 	return 0;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH 3/8] ARM: EXYNOS4: Divorce mct from local timer API
  2013-02-22  7:27 [PATCH 0/8] Remove ARM local timer API Stephen Boyd
  2013-02-22  7:27 ` [PATCH 1/8] ARM: smp: Lower rating of dummy broadcast device Stephen Boyd
  2013-02-22  7:27 ` [PATCH 2/8] ARM: smp_twd: Divorce smp_twd from local timer API Stephen Boyd
@ 2013-02-22  7:27 ` Stephen Boyd
  2013-02-22  7:27 ` [PATCH 4/8] ARM: PRIMA2: Divorce timer-marco " Stephen Boyd
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 19+ messages in thread
From: Stephen Boyd @ 2013-02-22  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

Separate the mct local timers from the local timer API. This will
allow us to remove ARM local timer support in the near future and
gets us closer to moving this driver to drivers/clocksource.

Cc: Kukjin Kim <kgene.kim@samsung.com>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
 arch/arm/mach-exynos/mct.c | 53 ++++++++++++++++++++++++++++++++--------------
 1 file changed, 37 insertions(+), 16 deletions(-)

diff --git a/arch/arm/mach-exynos/mct.c b/arch/arm/mach-exynos/mct.c
index c9d6650..5a9a73f 100644
--- a/arch/arm/mach-exynos/mct.c
+++ b/arch/arm/mach-exynos/mct.c
@@ -16,13 +16,13 @@
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/clockchips.h>
+#include <linux/cpu.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/percpu.h>
 #include <linux/of.h>
 
 #include <asm/arch_timer.h>
-#include <asm/localtimer.h>
 
 #include <plat/cpu.h>
 
@@ -42,7 +42,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];
 };
@@ -264,8 +264,6 @@ static void exynos4_clockevent_init(void)
 		setup_irq(EXYNOS4_IRQ_MCT_G0, &mct_comp_event_irq);
 }
 
-#ifdef CONFIG_LOCAL_TIMERS
-
 static DEFINE_PER_CPU(struct mct_clock_event_device, percpu_mct_tick);
 
 /* Clock event handling */
@@ -338,7 +336,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.
@@ -360,7 +358,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);
 
@@ -388,7 +386,6 @@ static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt)
 	int mct_lx_irq;
 
 	mevt = this_cpu_ptr(&percpu_mct_tick);
-	mevt->evt = evt;
 
 	mevt->base = EXYNOS4_MCT_L_BASE(cpu);
 	sprintf(mevt->name, "mct_tick%d", cpu);
@@ -426,7 +423,7 @@ static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt)
 	return 0;
 }
 
-static void exynos4_local_timer_stop(struct clock_event_device *evt)
+static void __cpuinit exynos4_local_timer_stop(struct clock_event_device *evt)
 {
 	unsigned int cpu = smp_processor_id();
 	evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
@@ -439,22 +436,38 @@ static void exynos4_local_timer_stop(struct clock_event_device *evt)
 		disable_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER);
 }
 
-static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = {
-	.setup	= exynos4_local_timer_setup,
-	.stop	= exynos4_local_timer_stop,
+static int __cpuinit exynos4_mct_cpu_notify(struct notifier_block *self,
+					   unsigned long action, void *hcpu)
+{
+	struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
+	struct clock_event_device *evt = &mevt->evt;
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_STARTING:
+		exynos4_local_timer_setup(evt);
+		break;
+	case CPU_DYING:
+		exynos4_local_timer_stop(evt);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block exynos4_mct_cpu_nb __cpuinitdata = {
+	.notifier_call = exynos4_mct_cpu_notify,
 };
-#endif /* CONFIG_LOCAL_TIMERS */
 
 static void __init exynos4_timer_resources(void)
 {
+	int err;
+	struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
 	struct clk *mct_clk;
 	mct_clk = clk_get(NULL, "xtal");
 
 	clk_rate = clk_get_rate(mct_clk);
 
-#ifdef CONFIG_LOCAL_TIMERS
 	if (mct_int_type == MCT_INT_PPI) {
-		int err;
 
 		err = request_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER,
 					 exynos4_mct_tick_isr, "MCT",
@@ -463,8 +476,16 @@ static void __init exynos4_timer_resources(void)
 		     EXYNOS_IRQ_MCT_LOCALTIMER, err);
 	}
 
-	local_timer_register(&exynos4_mct_tick_ops);
-#endif /* CONFIG_LOCAL_TIMERS */
+	err = register_cpu_notifier(&exynos4_mct_cpu_nb);
+	if (err)
+		goto out_irq;
+
+	/* Immediately configure the timer on the boot CPU */
+	exynos4_local_timer_setup(&mevt->evt);
+	return;
+
+out_irq:
+	free_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER, &percpu_mct_tick);
 }
 
 void __init exynos4_timer_init(void)
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH 4/8] ARM: PRIMA2: Divorce timer-marco from local timer API
  2013-02-22  7:27 [PATCH 0/8] Remove ARM local timer API Stephen Boyd
                   ` (2 preceding siblings ...)
  2013-02-22  7:27 ` [PATCH 3/8] ARM: EXYNOS4: Divorce mct " Stephen Boyd
@ 2013-02-22  7:27 ` Stephen Boyd
  2013-02-22  7:27 ` [PATCH 5/8] ARM: MSM: Divorce msm_timer " Stephen Boyd
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 19+ messages in thread
From: Stephen Boyd @ 2013-02-22  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

Separate the marco local timers from the local timer API. This
will allow us to remove ARM local timer support in the near future
and gets us closer to moving this driver to drivers/clocksource.

Cc: Barry Song <baohua.song@csr.com>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
 arch/arm/mach-prima2/timer-marco.c | 98 ++++++++++++++++++++------------------
 1 file changed, 52 insertions(+), 46 deletions(-)

diff --git a/arch/arm/mach-prima2/timer-marco.c b/arch/arm/mach-prima2/timer-marco.c
index f4eea2e..d54aac2 100644
--- a/arch/arm/mach-prima2/timer-marco.c
+++ b/arch/arm/mach-prima2/timer-marco.c
@@ -10,6 +10,7 @@
 #include <linux/interrupt.h>
 #include <linux/clockchips.h>
 #include <linux/clocksource.h>
+#include <linux/cpu.h>
 #include <linux/bitops.h>
 #include <linux/irq.h>
 #include <linux/clk.h>
@@ -18,7 +19,6 @@
 #include <linux/of_irq.h>
 #include <linux/of_address.h>
 #include <asm/sched_clock.h>
-#include <asm/localtimer.h>
 #include <asm/mach/time.h>
 
 #include "common.h"
@@ -154,13 +154,7 @@ static void sirfsoc_clocksource_resume(struct clocksource *cs)
 		BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
 }
 
-static struct clock_event_device sirfsoc_clockevent = {
-	.name = "sirfsoc_clockevent",
-	.rating = 200,
-	.features = CLOCK_EVT_FEAT_ONESHOT,
-	.set_mode = sirfsoc_timer_set_mode,
-	.set_next_event = sirfsoc_timer_set_next_event,
-};
+static struct clock_event_device __percpu *sirfsoc_clockevent;
 
 static struct clocksource sirfsoc_clocksource = {
 	.name = "sirfsoc_clocksource",
@@ -176,11 +170,8 @@ static struct irqaction sirfsoc_timer_irq = {
 	.name = "sirfsoc_timer0",
 	.flags = IRQF_TIMER | IRQF_NOBALANCING,
 	.handler = sirfsoc_timer_interrupt,
-	.dev_id = &sirfsoc_clockevent,
 };
 
-#ifdef CONFIG_LOCAL_TIMERS
-
 static struct irqaction sirfsoc_timer1_irq = {
 	.name = "sirfsoc_timer1",
 	.flags = IRQF_TIMER | IRQF_NOBALANCING,
@@ -189,56 +180,75 @@ static struct irqaction sirfsoc_timer1_irq = {
 
 static int __cpuinit sirfsoc_local_timer_setup(struct clock_event_device *ce)
 {
-	/* Use existing clock_event for cpu 0 */
-	if (!smp_processor_id())
-		return 0;
+	int cpu = smp_processor_id();
+	struct irqaction *action;
+
+	if (cpu == 0)
+		action = &sirfsoc_timer_irq;
+	else
+		action = &sirfsoc_timer1_irq;
 
-	ce->irq = sirfsoc_timer1_irq.irq;
+	ce->irq = action->irq;
 	ce->name = "local_timer";
-	ce->features = sirfsoc_clockevent.features;
-	ce->rating = sirfsoc_clockevent.rating;
+	ce->features = CLOCK_EVT_FEAT_ONESHOT;
+	ce->rating = 200;
 	ce->set_mode = sirfsoc_timer_set_mode;
 	ce->set_next_event = sirfsoc_timer_set_next_event;
-	ce->shift = sirfsoc_clockevent.shift;
-	ce->mult = sirfsoc_clockevent.mult;
-	ce->max_delta_ns = sirfsoc_clockevent.max_delta_ns;
-	ce->min_delta_ns = sirfsoc_clockevent.min_delta_ns;
+	clockevents_calc_mult_shift(ce, CLOCK_TICK_RATE, 60);
+	ce->max_delta_ns = clockevent_delta2ns(-2, ce);
+	ce->min_delta_ns = clockevent_delta2ns(2, ce);
+	ce->cpumask = cpumask_of(cpu);
 
-	sirfsoc_timer1_irq.dev_id = ce;
-	BUG_ON(setup_irq(ce->irq, &sirfsoc_timer1_irq));
-	irq_set_affinity(sirfsoc_timer1_irq.irq, cpumask_of(1));
+	action->dev_id = ce;
+	BUG_ON(setup_irq(ce->irq, action));
+	irq_set_affinity(action->irq, cpumask_of(cpu));
 
 	clockevents_register_device(ce);
 	return 0;
 }
 
-static void sirfsoc_local_timer_stop(struct clock_event_device *ce)
+static void __cpuinit sirfsoc_local_timer_stop(struct clock_event_device *ce)
 {
+	int cpu = smp_processor_id();
+
 	sirfsoc_timer_count_disable(1);
 
-	remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq);
+	if (cpu == 0)
+		remove_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq);
+	else
+		remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq);
+}
+
+static int __cpuinit sirfsoc_cpu_notify(struct notifier_block *self,
+					   unsigned long action, void *hcpu)
+{
+	struct clock_event_device *evt = this_cpu_ptr(sirfsoc_clockevent);
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_STARTING:
+		sirfsoc_local_timer_setup(evt);
+		break;
+	case CPU_DYING:
+		sirfsoc_local_timer_stop(evt);
+		break;
+	}
+
+	return NOTIFY_OK;
 }
 
-static struct local_timer_ops sirfsoc_local_timer_ops __cpuinitdata = {
-	.setup	= sirfsoc_local_timer_setup,
-	.stop	= sirfsoc_local_timer_stop,
+static struct notifier_block sirfsoc_cpu_nb __cpuinitdata = {
+	.notifier_call = sirfsoc_cpu_notify,
 };
-#endif /* CONFIG_LOCAL_TIMERS */
 
 static void __init sirfsoc_clockevent_init(void)
 {
-	clockevents_calc_mult_shift(&sirfsoc_clockevent, CLOCK_TICK_RATE, 60);
-
-	sirfsoc_clockevent.max_delta_ns =
-		clockevent_delta2ns(-2, &sirfsoc_clockevent);
-	sirfsoc_clockevent.min_delta_ns =
-		clockevent_delta2ns(2, &sirfsoc_clockevent);
-
-	sirfsoc_clockevent.cpumask = cpumask_of(0);
-	clockevents_register_device(&sirfsoc_clockevent);
-#ifdef CONFIG_LOCAL_TIMERS
-	local_timer_register(&sirfsoc_local_timer_ops);
-#endif
+	sirfsoc_clockevent = alloc_percpu(struct clock_event_device);
+	BUG_ON(!sirfsoc_clockevent);
+
+	BUG_ON(register_cpu_notifier(&sirfsoc_cpu_nb));
+
+	/* Immediately configure the timer on the boot CPU */
+	sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent));
 }
 
 /* initialize the kernel jiffy timer source */
@@ -281,8 +291,6 @@ void __init sirfsoc_marco_timer_init(void)
 
 	BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE));
 
-	BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq));
-
 	sirfsoc_clockevent_init();
 }
 
@@ -306,11 +314,9 @@ static void __init sirfsoc_of_timer_map(void)
 	if (!sirfsoc_timer_irq.irq)
 		panic("No irq passed for timer0 via DT\n");
 
-#ifdef CONFIG_LOCAL_TIMERS
 	sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1);
 	if (!sirfsoc_timer1_irq.irq)
 		panic("No irq passed for timer1 via DT\n");
-#endif
 
 	of_node_put(np);
 }
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH 5/8] ARM: MSM: Divorce msm_timer from local timer API
  2013-02-22  7:27 [PATCH 0/8] Remove ARM local timer API Stephen Boyd
                   ` (3 preceding siblings ...)
  2013-02-22  7:27 ` [PATCH 4/8] ARM: PRIMA2: Divorce timer-marco " Stephen Boyd
@ 2013-02-22  7:27 ` Stephen Boyd
  2013-03-05 19:04   ` David Brown
  2013-02-22  7:27 ` [PATCH 6/8] clocksource: time-armada-370-xp: Fix sparse warning Stephen Boyd
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 19+ messages in thread
From: Stephen Boyd @ 2013-02-22  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

Separate the msm_timer from the local timer API. This will allow
us to remove ARM local timer support in the near future and gets
us closer to moving this driver to drivers/clocksource.

Cc: David Brown <davidb@codeaurora.org>
Cc: Daniel Walker <dwalker@fifo99.com>
Cc: Bryan Huntsman <bryanh@codeaurora.org>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
 arch/arm/mach-msm/timer.c | 125 +++++++++++++++++++++++++---------------------
 1 file changed, 67 insertions(+), 58 deletions(-)

diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 2969027..4675c5e 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -16,6 +16,7 @@
 
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
+#include <linux/cpu.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
@@ -25,7 +26,6 @@
 #include <linux/of_irq.h>
 
 #include <asm/mach/time.h>
-#include <asm/localtimer.h>
 #include <asm/sched_clock.h>
 
 #include "common.h"
@@ -46,7 +46,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);
@@ -90,18 +90,7 @@ static void msm_timer_set_mode(enum clock_event_mode mode,
 	writel_relaxed(ctrl, event_base + TIMER_ENABLE);
 }
 
-static struct clock_event_device msm_clockevent = {
-	.name		= "gp_timer",
-	.features	= CLOCK_EVT_FEAT_ONESHOT,
-	.rating		= 200,
-	.set_next_event	= msm_timer_set_next_event,
-	.set_mode	= msm_timer_set_mode,
-};
-
-static union {
-	struct clock_event_device *evt;
-	struct clock_event_device * __percpu *percpu_evt;
-} msm_evt;
+static struct clock_event_device __percpu *msm_evt;
 
 static void __iomem *source_base;
 
@@ -127,40 +116,66 @@ static struct clocksource msm_clocksource = {
 	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-#ifdef CONFIG_LOCAL_TIMERS
+static int msm_timer_irq;
+static int msm_timer_has_ppi;
+
 static int __cpuinit msm_local_timer_setup(struct clock_event_device *evt)
 {
-	/* Use existing clock_event for cpu 0 */
-	if (!smp_processor_id())
-		return 0;
+	int cpu = smp_processor_id();
+	int err;
 
 	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->irq = msm_timer_irq;
 	evt->name = "local_timer";
-	evt->features = msm_clockevent.features;
-	evt->rating = msm_clockevent.rating;
+	evt->features = CLOCK_EVT_FEAT_ONESHOT;
+	evt->rating = 200;
 	evt->set_mode = msm_timer_set_mode;
 	evt->set_next_event = msm_timer_set_next_event;
+	evt->cpumask = cpumask_of(cpu);
+
+	clockevents_config_and_register(evt, GPT_HZ, 4, 0xffffffff);
+
+	if (msm_timer_has_ppi) {
+		enable_percpu_irq(evt->irq, IRQ_TYPE_EDGE_RISING);
+	} else {
+		err = request_irq(evt->irq, msm_timer_interrupt,
+				IRQF_TIMER | IRQF_NOBALANCING |
+				IRQF_TRIGGER_RISING, "gp_timer", evt);
+		if (err)
+			pr_err("request_irq failed\n");
+	}
 
-	*__this_cpu_ptr(msm_evt.percpu_evt) = evt;
-	clockevents_config_and_register(evt, GPT_HZ, 4, 0xf0000000);
-	enable_percpu_irq(evt->irq, IRQ_TYPE_EDGE_RISING);
 	return 0;
 }
 
-static void msm_local_timer_stop(struct clock_event_device *evt)
+static void __cpuinit msm_local_timer_stop(struct clock_event_device *evt)
 {
 	evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
 	disable_percpu_irq(evt->irq);
 }
 
-static struct local_timer_ops msm_local_timer_ops __cpuinitdata = {
-	.setup	= msm_local_timer_setup,
-	.stop	= msm_local_timer_stop,
+static int __cpuinit msm_timer_cpu_notify(struct notifier_block *self,
+					   unsigned long action, void *hcpu)
+{
+	struct clock_event_device *evt = this_cpu_ptr(msm_evt);
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_STARTING:
+		msm_local_timer_setup(evt);
+		break;
+	case CPU_DYING:
+		msm_local_timer_stop(evt);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block msm_timer_cpu_nb __cpuinitdata = {
+	.notifier_call = msm_timer_cpu_notify,
 };
-#endif /* CONFIG_LOCAL_TIMERS */
 
 static notrace u32 msm_sched_clock_read(void)
 {
@@ -170,41 +185,35 @@ static notrace u32 msm_sched_clock_read(void)
 static void __init msm_timer_init(u32 dgt_hz, int sched_bits, int irq,
 				  bool percpu)
 {
-	struct clock_event_device *ce = &msm_clockevent;
 	struct clocksource *cs = &msm_clocksource;
-	int res;
+	int res = 0;
 
-	writel_relaxed(0, event_base + TIMER_ENABLE);
-	writel_relaxed(0, event_base + TIMER_CLEAR);
-	writel_relaxed(~0, event_base + TIMER_MATCH_VAL);
-	ce->cpumask = cpumask_of(0);
-	ce->irq = irq;
-
-	clockevents_config_and_register(ce, GPT_HZ, 4, 0xffffffff);
-	if (percpu) {
-		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);
+	msm_timer_irq = irq;
+	msm_timer_has_ppi = percpu;
+
+	msm_evt = alloc_percpu(struct clock_event_device);
+	if (!msm_evt) {
+		pr_err("memory allocation failed for clockevents\n");
+		goto err;
+	}
+
+	if (percpu)
+		res = request_percpu_irq(irq, msm_timer_interrupt,
+					 "gp_timer", msm_evt);
+
+	if (res) {
+		pr_err("request_percpu_irq failed\n");
+	} else {
+		res = register_cpu_notifier(&msm_timer_cpu_nb);
+		if (res) {
+			free_percpu_irq(irq, msm_evt);
 			goto err;
 		}
-		*__this_cpu_ptr(msm_evt.percpu_evt) = ce;
-		res = request_percpu_irq(ce->irq, msm_timer_interrupt,
-					 ce->name, msm_evt.percpu_evt);
-		if (!res) {
-			enable_percpu_irq(ce->irq, IRQ_TYPE_EDGE_RISING);
-#ifdef CONFIG_LOCAL_TIMERS
-			local_timer_register(&msm_local_timer_ops);
-#endif
-		}
-	} else {
-		msm_evt.evt = ce;
-		res = request_irq(ce->irq, msm_timer_interrupt,
-				  IRQF_TIMER | IRQF_NOBALANCING |
-				  IRQF_TRIGGER_RISING, ce->name, &msm_evt.evt);
+
+		/* Immediately configure the timer on the boot CPU */
+		msm_local_timer_setup(this_cpu_ptr(msm_evt));
 	}
 
-	if (res)
-		pr_err("request_irq failed for %s\n", ce->name);
 err:
 	writel_relaxed(TIMER_ENABLE_EN, source_base + TIMER_ENABLE);
 	res = clocksource_register_hz(cs, dgt_hz);
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH 6/8] clocksource: time-armada-370-xp: Fix sparse warning
  2013-02-22  7:27 [PATCH 0/8] Remove ARM local timer API Stephen Boyd
                   ` (4 preceding siblings ...)
  2013-02-22  7:27 ` [PATCH 5/8] ARM: MSM: Divorce msm_timer " Stephen Boyd
@ 2013-02-22  7:27 ` Stephen Boyd
  2013-02-22  7:27 ` [PATCH 7/8] clocksource: time-armada-370-xp: Divorce from local timer API Stephen Boyd
  2013-02-22  7:27 ` [PATCH 8/8] ARM: smp: Remove " Stephen Boyd
  7 siblings, 0 replies; 19+ messages in thread
From: Stephen Boyd @ 2013-02-22  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

drivers/clocksource/time-armada-370-xp.c:217:13: warning: symbol
'armada_370_xp_timer_init' was not declared. Should it be static?

Also remove the __init marking in the prototype as it's
unnecessary and drop the init.h file.

Cc: Gregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
 drivers/clocksource/time-armada-370-xp.c | 3 ++-
 include/linux/time-armada-370-xp.h       | 4 +---
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c
index 47a6730..efe4aef 100644
--- a/drivers/clocksource/time-armada-370-xp.c
+++ b/drivers/clocksource/time-armada-370-xp.c
@@ -27,10 +27,11 @@
 #include <linux/of_address.h>
 #include <linux/irq.h>
 #include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/time-armada-370-xp.h>
 
 #include <asm/sched_clock.h>
 #include <asm/localtimer.h>
-#include <linux/percpu.h>
 /*
  * Timer block registers.
  */
diff --git a/include/linux/time-armada-370-xp.h b/include/linux/time-armada-370-xp.h
index dfdfdc0..6fb0856 100644
--- a/include/linux/time-armada-370-xp.h
+++ b/include/linux/time-armada-370-xp.h
@@ -11,8 +11,6 @@
 #ifndef __TIME_ARMADA_370_XPPRCMU_H
 #define __TIME_ARMADA_370_XPPRCMU_H
 
-#include <linux/init.h>
-
-void __init armada_370_xp_timer_init(void);
+void armada_370_xp_timer_init(void);
 
 #endif
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH 7/8] clocksource: time-armada-370-xp: Divorce from local timer API
  2013-02-22  7:27 [PATCH 0/8] Remove ARM local timer API Stephen Boyd
                   ` (5 preceding siblings ...)
  2013-02-22  7:27 ` [PATCH 6/8] clocksource: time-armada-370-xp: Fix sparse warning Stephen Boyd
@ 2013-02-22  7:27 ` Stephen Boyd
  2013-02-22  7:27 ` [PATCH 8/8] ARM: smp: Remove " Stephen Boyd
  7 siblings, 0 replies; 19+ messages in thread
From: Stephen Boyd @ 2013-02-22  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

Separate the armada 370xp local timers from the local timer API.
This will allow us to remove ARM local timer support in the near
future and makes this driver multi-architecture friendly.

Cc: Gregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
 drivers/clocksource/time-armada-370-xp.c | 85 ++++++++++++++------------------
 1 file changed, 38 insertions(+), 47 deletions(-)

diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c
index efe4aef..ee2e50c5 100644
--- a/drivers/clocksource/time-armada-370-xp.c
+++ b/drivers/clocksource/time-armada-370-xp.c
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/kernel.h>
 #include <linux/clk.h>
+#include <linux/cpu.h>
 #include <linux/timer.h>
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
@@ -31,7 +32,6 @@
 #include <linux/time-armada-370-xp.h>
 
 #include <asm/sched_clock.h>
-#include <asm/localtimer.h>
 /*
  * Timer block registers.
  */
@@ -70,7 +70,7 @@ static bool timer25Mhz = true;
  */
 static u32 ticks_per_jiffy;
 
-static struct clock_event_device __percpu **percpu_armada_370_xp_evt;
+static struct clock_event_device __percpu *armada_370_xp_evt;
 
 static u32 notrace armada_370_xp_read_sched_clock(void)
 {
@@ -143,14 +143,7 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode,
 	}
 }
 
-static struct clock_event_device armada_370_xp_clkevt = {
-	.name		= "armada_370_xp_per_cpu_tick",
-	.features	= CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
-	.shift		= 32,
-	.rating		= 300,
-	.set_next_event	= armada_370_xp_clkevt_next_event,
-	.set_mode	= armada_370_xp_clkevt_mode,
-};
+static int armada_370_xp_clkevt_irq;
 
 static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id)
 {
@@ -173,42 +166,53 @@ static int __cpuinit armada_370_xp_timer_setup(struct clock_event_device *evt)
 	u32 u;
 	int cpu = smp_processor_id();
 
-	/* Use existing clock_event for cpu 0 */
-	if (!smp_processor_id())
-		return 0;
-
 	u = readl(local_base + TIMER_CTRL_OFF);
 	if (timer25Mhz)
 		writel(u | TIMER0_25MHZ, local_base + TIMER_CTRL_OFF);
 	else
 		writel(u & ~TIMER0_25MHZ, local_base + TIMER_CTRL_OFF);
 
-	evt->name		= armada_370_xp_clkevt.name;
-	evt->irq		= armada_370_xp_clkevt.irq;
-	evt->features		= armada_370_xp_clkevt.features;
-	evt->shift		= armada_370_xp_clkevt.shift;
-	evt->rating		= armada_370_xp_clkevt.rating,
+	evt->name		= "armada_370_xp_per_cpu_tick",
+	evt->features		= CLOCK_EVT_FEAT_ONESHOT |
+				  CLOCK_EVT_FEAT_PERIODIC;
+	evt->shift		= 32,
+	evt->rating		= 300,
 	evt->set_next_event	= armada_370_xp_clkevt_next_event,
 	evt->set_mode		= armada_370_xp_clkevt_mode,
+	evt->irq		= armada_370_xp_clkevt_irq;
 	evt->cpumask		= cpumask_of(cpu);
 
-	*__this_cpu_ptr(percpu_armada_370_xp_evt) = evt;
-
 	clockevents_config_and_register(evt, timer_clk, 1, 0xfffffffe);
 	enable_percpu_irq(evt->irq, 0);
 
 	return 0;
 }
 
-static void  armada_370_xp_timer_stop(struct clock_event_device *evt)
+static void __cpuinit armada_370_xp_timer_stop(struct clock_event_device *evt)
 {
 	evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
 	disable_percpu_irq(evt->irq);
 }
 
-static struct local_timer_ops armada_370_xp_local_timer_ops __cpuinitdata = {
-	.setup	= armada_370_xp_timer_setup,
-	.stop	=  armada_370_xp_timer_stop,
+static int __cpuinit armada_370_xp_timer_cpu_notify(struct notifier_block *self,
+					   unsigned long action, void *hcpu)
+{
+	struct clock_event_device *evt = this_cpu_ptr(armada_370_xp_evt);
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_STARTING:
+		armada_370_xp_timer_setup(evt);
+		break;
+	case CPU_DYING:
+		armada_370_xp_timer_stop(evt);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block armada_370_xp_timer_cpu_nb __cpuinitdata = {
+	.notifier_call = armada_370_xp_timer_cpu_notify,
 };
 
 void __init armada_370_xp_timer_init(void)
@@ -224,9 +228,6 @@ void __init armada_370_xp_timer_init(void)
 
 	if (of_find_property(np, "marvell,timer-25Mhz", NULL)) {
 		/* The fixed 25MHz timer is available so let's use it */
-		u = readl(local_base + TIMER_CTRL_OFF);
-		writel(u | TIMER0_25MHZ,
-		       local_base + TIMER_CTRL_OFF);
 		u = readl(timer_base + TIMER_CTRL_OFF);
 		writel(u | TIMER0_25MHZ,
 		       timer_base + TIMER_CTRL_OFF);
@@ -236,9 +237,6 @@ void __init armada_370_xp_timer_init(void)
 		struct clk *clk = of_clk_get(np, 0);
 		WARN_ON(IS_ERR(clk));
 		rate =  clk_get_rate(clk);
-		u = readl(local_base + TIMER_CTRL_OFF);
-		writel(u & ~(TIMER0_25MHZ),
-		       local_base + TIMER_CTRL_OFF);
 
 		u = readl(timer_base + TIMER_CTRL_OFF);
 		writel(u & ~(TIMER0_25MHZ),
@@ -252,7 +250,7 @@ void __init armada_370_xp_timer_init(void)
 	 * We use timer 0 as clocksource, and private(local) timer 0
 	 * for clockevents
 	 */
-	armada_370_xp_clkevt.irq = irq_of_parse_and_map(np, 4);
+	armada_370_xp_clkevt_irq = irq_of_parse_and_map(np, 4);
 
 	ticks_per_jiffy = (timer_clk + HZ / 2) / HZ;
 
@@ -277,26 +275,19 @@ void __init armada_370_xp_timer_init(void)
 			      "armada_370_xp_clocksource",
 			      timer_clk, 300, 32, clocksource_mmio_readl_down);
 
-	/* Register the clockevent on the private timer of CPU 0 */
-	armada_370_xp_clkevt.cpumask = cpumask_of(0);
-	clockevents_config_and_register(&armada_370_xp_clkevt,
-					timer_clk, 1, 0xfffffffe);
+	register_cpu_notifier(&armada_370_xp_timer_cpu_nb);
 
-	percpu_armada_370_xp_evt = alloc_percpu(struct clock_event_device *);
+	armada_370_xp_evt = alloc_percpu(struct clock_event_device);
 
 
 	/*
 	 * Setup clockevent timer (interrupt-driven).
 	 */
-	*__this_cpu_ptr(percpu_armada_370_xp_evt) = &armada_370_xp_clkevt;
-	res = request_percpu_irq(armada_370_xp_clkevt.irq,
+	res = request_percpu_irq(armada_370_xp_clkevt_irq,
 				armada_370_xp_timer_interrupt,
-				armada_370_xp_clkevt.name,
-				percpu_armada_370_xp_evt);
-	if (!res) {
-		enable_percpu_irq(armada_370_xp_clkevt.irq, 0);
-#ifdef CONFIG_LOCAL_TIMERS
-		local_timer_register(&armada_370_xp_local_timer_ops);
-#endif
-	}
+				"armada_370_xp_per_cpu_tick",
+				armada_370_xp_evt);
+	/* Immediately configure the timer on the boot CPU */
+	if (!res)
+		armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt));
 }
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH 8/8] ARM: smp: Remove local timer API
  2013-02-22  7:27 [PATCH 0/8] Remove ARM local timer API Stephen Boyd
                   ` (6 preceding siblings ...)
  2013-02-22  7:27 ` [PATCH 7/8] clocksource: time-armada-370-xp: Divorce from local timer API Stephen Boyd
@ 2013-02-22  7:27 ` Stephen Boyd
  2013-02-22 11:15   ` Mark Rutland
  7 siblings, 1 reply; 19+ messages in thread
From: Stephen Boyd @ 2013-02-22  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

There are no more users of this API, remove it.

Cc: Russell King <linux@arm.linux.org.uk>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
 arch/arm/Kconfig                  | 12 +------
 arch/arm/include/asm/localtimer.h | 34 --------------------
 arch/arm/kernel/smp.c             | 67 ++++++---------------------------------
 arch/arm/mach-omap2/Kconfig       |  1 -
 arch/arm/mach-omap2/timer.c       |  7 ----
 5 files changed, 11 insertions(+), 110 deletions(-)
 delete mode 100644 arch/arm/include/asm/localtimer.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index dedf02b..7d4338d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1527,6 +1527,7 @@ config SMP
 	depends on HAVE_SMP
 	depends on MMU
 	select HAVE_ARM_SCU if !ARCH_MSM_SCORPIONMP
+	select HAVE_ARM_TWD if (!ARCH_MSM_SCORPIONMP && !EXYNOS4_MCT)
 	select USE_GENERIC_SMP_HELPERS
 	help
 	  This enables support for systems with more than one CPU. If you have
@@ -1646,17 +1647,6 @@ config ARM_PSCI
 	  0022A ("Power State Coordination Interface System Software on
 	  ARM processors").
 
-config LOCAL_TIMERS
-	bool "Use local timer interrupts"
-	depends on SMP
-	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
-	  accounting to be spread across the timer interval, preventing a
-	  "thundering herd" at every timer tick.
-
 config ARCH_NR_GPIO
 	int
 	default 1024 if ARCH_SHMOBILE || ARCH_TEGRA
diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h
deleted file mode 100644
index f77ffc1..0000000
--- a/arch/arm/include/asm/localtimer.h
+++ /dev/null
@@ -1,34 +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>
-
-struct clock_event_device;
-
-struct local_timer_ops {
-	int  (*setup)(struct clock_event_device *);
-	void (*stop)(struct clock_event_device *);
-};
-
-#ifdef CONFIG_LOCAL_TIMERS
-/*
- * Register a local timer driver
- */
-int local_timer_register(struct local_timer_ops *);
-#else
-static inline int local_timer_register(struct local_timer_ops *ops)
-{
-	return -ENXIO;
-}
-#endif
-
-#endif
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 2d5197d..f628c79 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -41,7 +41,6 @@
 #include <asm/sections.h>
 #include <asm/tlbflush.h>
 #include <asm/ptrace.h>
-#include <asm/localtimer.h>
 #include <asm/smp_plat.h>
 #include <asm/virt.h>
 #include <asm/mach/arch.h>
@@ -133,8 +132,6 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-static void percpu_timer_stop(void);
-
 static int platform_cpu_kill(unsigned int cpu)
 {
 	if (smp_ops.cpu_kill)
@@ -178,11 +175,6 @@ int __cpuinit __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.
 	 *
@@ -269,7 +261,7 @@ static void __cpuinit smp_store_cpu_info(unsigned int cpuid)
 	store_cpu_topology(cpuid);
 }
 
-static void percpu_timer_setup(void);
+static void broadcast_timer_setup(void);
 
 /*
  * This is the secondary CPU boot entry.  We're using this CPUs
@@ -325,9 +317,9 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
 	complete(&cpu_running);
 
 	/*
-	 * Setup the percpu timer for this CPU.
+	 * Setup the dummy broadcast timer for this CPU.
 	 */
-	percpu_timer_setup();
+	broadcast_timer_setup();
 
 	local_irq_enable();
 	local_fiq_enable();
@@ -375,10 +367,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
+		 * Enable the dummy 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
@@ -473,8 +465,12 @@ 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->cpumask	= cpumask_of(cpu);
 	evt->name	= "dummy_timer";
 	evt->features	= CLOCK_EVT_FEAT_ONESHOT |
 			  CLOCK_EVT_FEAT_PERIODIC |
@@ -486,49 +482,6 @@ static void __cpuinit broadcast_timer_setup(struct clock_event_device *evt)
 	clockevents_register_device(evt);
 }
 
-static struct local_timer_ops *lt_ops;
-
-#ifdef CONFIG_LOCAL_TIMERS
-int local_timer_register(struct local_timer_ops *ops)
-{
-	if (!is_smp() || !setup_max_cpus)
-		return -ENXIO;
-
-	if (lt_ops)
-		return -EBUSY;
-
-	lt_ops = ops;
-	return 0;
-}
-#endif
-
-static 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);
-
-	if (!lt_ops || lt_ops->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);
-
-	if (lt_ops)
-		lt_ops->stop(evt);
-}
-#endif
-
 static DEFINE_RAW_SPINLOCK(stop_lock);
 
 /*
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 49ac3df..6e1f871 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -88,7 +88,6 @@ config ARCH_OMAP4
 	select CACHE_L2X0
 	select CPU_V7
 	select HAVE_SMP
-	select LOCAL_TIMERS if SMP
 	select OMAP_INTERCONNECT
 	select PL310_ERRATA_588369
 	select PL310_ERRATA_727915
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 2bdd4cf..c00a8f8 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -587,7 +587,6 @@ OMAP_SYS_GP_TIMER_INIT(3_am33xx, 1, OMAP4_MPU_SOURCE, "ti,timer-alwon",
 #ifdef CONFIG_ARCH_OMAP4
 OMAP_SYS_32K_TIMER_INIT(4, 1, OMAP4_32K_SOURCE, "ti,timer-alwon",
 			2, OMAP4_MPU_SOURCE);
-#ifdef CONFIG_LOCAL_TIMERS
 static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, OMAP44XX_LOCAL_TWD_BASE, 29);
 void __init omap4_local_timer_init(void)
 {
@@ -606,12 +605,6 @@ void __init omap4_local_timer_init(void)
 			pr_err("twd_local_timer_register failed %d\n", err);
 	}
 }
-#else /* CONFIG_LOCAL_TIMERS */
-void __init omap4_local_timer_init(void)
-{
-	omap4_sync32k_timer_init();
-}
-#endif /* CONFIG_LOCAL_TIMERS */
 #endif /* CONFIG_ARCH_OMAP4 */
 
 #ifdef CONFIG_SOC_OMAP5
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH 8/8] ARM: smp: Remove local timer API
  2013-02-22  7:27 ` [PATCH 8/8] ARM: smp: Remove " Stephen Boyd
@ 2013-02-22 11:15   ` Mark Rutland
  2013-02-22 16:25     ` Paul Mundt
  2013-02-24  2:37     ` Stephen Boyd
  0 siblings, 2 replies; 19+ messages in thread
From: Mark Rutland @ 2013-02-22 11:15 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Stephen,

One thing that struck me when I was fiddling with the broadcast mechanism was
that it should be possible to have a generic dummy timer implementation. As
long as the architecture calls notifiers at the appropriate times, it should
look like any other timer driver (apart from not touching any hardware). It just
needs to depend on ARCH_HAS_TICK_BROADCAST.

I believe it shouldn't be too difficult to implement, though I may be blind to
some problems.

Otherwise, I have a few comments on the patch below.

On Fri, Feb 22, 2013 at 07:27:19AM +0000, Stephen Boyd wrote:
> There are no more users of this API, remove it.

As we're leaving the dummy timers, it'd be worth explaining why in the commit
message.

> 
> Cc: Russell King <linux@arm.linux.org.uk>
> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> ---
>  arch/arm/Kconfig                  | 12 +------
>  arch/arm/include/asm/localtimer.h | 34 --------------------
>  arch/arm/kernel/smp.c             | 67 ++++++---------------------------------
>  arch/arm/mach-omap2/Kconfig       |  1 -
>  arch/arm/mach-omap2/timer.c       |  7 ----
>  5 files changed, 11 insertions(+), 110 deletions(-)
>  delete mode 100644 arch/arm/include/asm/localtimer.h
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index dedf02b..7d4338d 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -1527,6 +1527,7 @@ config SMP
>  	depends on HAVE_SMP
>  	depends on MMU
>  	select HAVE_ARM_SCU if !ARCH_MSM_SCORPIONMP
> +	select HAVE_ARM_TWD if (!ARCH_MSM_SCORPIONMP && !EXYNOS4_MCT)
>  	select USE_GENERIC_SMP_HELPERS
>  	help
>  	  This enables support for systems with more than one CPU. If you have

Should this have been in an earlier patch?

Why is it necessary?

[...]

> -static void percpu_timer_setup(void);
> +static void broadcast_timer_setup(void);
>  
>  /*
>   * This is the secondary CPU boot entry.  We're using this CPUs
> @@ -325,9 +317,9 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
>  	complete(&cpu_running);
>  
>  	/*
> -	 * Setup the percpu timer for this CPU.
> +	 * Setup the dummy broadcast timer for this CPU.

To me, calling something a broadcast timer makes it sound like it performs the
broadcast. We use the term "broadcast timer" elsewhere here (e.g.
broadcast_timer_setup), and I think it's any unnecessarily confusing term.

Might it be better to say "dummy timer" consistently?

[...]

> diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
> index 49ac3df..6e1f871 100644
> --- a/arch/arm/mach-omap2/Kconfig
> +++ b/arch/arm/mach-omap2/Kconfig
> @@ -88,7 +88,6 @@ config ARCH_OMAP4
>  	select CACHE_L2X0
>  	select CPU_V7
>  	select HAVE_SMP
> -	select LOCAL_TIMERS if SMP
>  	select OMAP_INTERCONNECT
>  	select PL310_ERRATA_588369
>  	select PL310_ERRATA_727915
> diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
> index 2bdd4cf..c00a8f8 100644
> --- a/arch/arm/mach-omap2/timer.c
> +++ b/arch/arm/mach-omap2/timer.c
> @@ -587,7 +587,6 @@ OMAP_SYS_GP_TIMER_INIT(3_am33xx, 1, OMAP4_MPU_SOURCE, "ti,timer-alwon",
>  #ifdef CONFIG_ARCH_OMAP4
>  OMAP_SYS_32K_TIMER_INIT(4, 1, OMAP4_32K_SOURCE, "ti,timer-alwon",
>  			2, OMAP4_MPU_SOURCE);
> -#ifdef CONFIG_LOCAL_TIMERS
>  static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, OMAP44XX_LOCAL_TWD_BASE, 29);
>  void __init omap4_local_timer_init(void)
>  {
> @@ -606,12 +605,6 @@ void __init omap4_local_timer_init(void)
>  			pr_err("twd_local_timer_register failed %d\n", err);
>  	}
>  }
> -#else /* CONFIG_LOCAL_TIMERS */
> -void __init omap4_local_timer_init(void)
> -{
> -	omap4_sync32k_timer_init();
> -}
> -#endif /* CONFIG_LOCAL_TIMERS */
>  #endif /* CONFIG_ARCH_OMAP4 */
>  
>  #ifdef CONFIG_SOC_OMAP5

I believe the above OMAP changes should have been in an earlier patch?

Thanks,
Mark.

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

* [PATCH 8/8] ARM: smp: Remove local timer API
  2013-02-22 11:15   ` Mark Rutland
@ 2013-02-22 16:25     ` Paul Mundt
  2013-02-25 13:40       ` Mark Rutland
  2013-02-24  2:37     ` Stephen Boyd
  1 sibling, 1 reply; 19+ messages in thread
From: Paul Mundt @ 2013-02-22 16:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Feb 22, 2013 at 11:15:45AM +0000, Mark Rutland wrote:
> One thing that struck me when I was fiddling with the broadcast mechanism was
> that it should be possible to have a generic dummy timer implementation. As
> long as the architecture calls notifiers at the appropriate times, it should
> look like any other timer driver (apart from not touching any hardware). It just
> needs to depend on ARCH_HAS_TICK_BROADCAST.
> 
> I believe it shouldn't be too difficult to implement, though I may be blind to
> some problems.
> 
It would be nice to have a generic dummy timer driver, quite a few
architectures could use it directly already. If no one beats me to it,
I'll give it a go as I convert the SH stuff over to using
ARCH_HAS_TICK_BROADCAST and killing off the local timer API there.

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

* [PATCH 8/8] ARM: smp: Remove local timer API
  2013-02-22 11:15   ` Mark Rutland
  2013-02-22 16:25     ` Paul Mundt
@ 2013-02-24  2:37     ` Stephen Boyd
  2013-02-25 13:44       ` Mark Rutland
  1 sibling, 1 reply; 19+ messages in thread
From: Stephen Boyd @ 2013-02-24  2:37 UTC (permalink / raw)
  To: linux-arm-kernel

On 2/22/2013 3:15 AM, Mark Rutland wrote:
> Hi Stephen,
>
> One thing that struck me when I was fiddling with the broadcast mechanism was
> that it should be possible to have a generic dummy timer implementation. As
> long as the architecture calls notifiers at the appropriate times, it should
> look like any other timer driver (apart from not touching any hardware). It just
> needs to depend on ARCH_HAS_TICK_BROADCAST.
>
> I believe it shouldn't be too difficult to implement, though I may be blind to
> some problems.

I completely agree and I was thinking the same thing while writing this
patchset.

>
> Otherwise, I have a few comments on the patch below.
>
> On Fri, Feb 22, 2013 at 07:27:19AM +0000, Stephen Boyd wrote:
>> There are no more users of this API, remove it.
> As we're leaving the dummy timers, it'd be worth explaining why in the commit
> message.

No problem.

>
>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>> index dedf02b..7d4338d 100644
>> --- a/arch/arm/Kconfig
>> +++ b/arch/arm/Kconfig
>> @@ -1527,6 +1527,7 @@ config SMP
>>  	depends on HAVE_SMP
>>  	depends on MMU
>>  	select HAVE_ARM_SCU if !ARCH_MSM_SCORPIONMP
>> +	select HAVE_ARM_TWD if (!ARCH_MSM_SCORPIONMP && !EXYNOS4_MCT)
>>  	select USE_GENERIC_SMP_HELPERS
>>  	help
>>  	  This enables support for systems with more than one CPU. If you have
> Should this have been in an earlier patch?

It could be part of the smp_twd patch if you like.

> Why is it necessary?

It shouldn't be. In fact, I sent a patchset a few months ago that pushed
down the TWD and SCU selects to the respective machines that need them.
I should resend that.

>
> [...]
>
>> -static void percpu_timer_setup(void);
>> +static void broadcast_timer_setup(void);
>>  
>>  /*
>>   * This is the secondary CPU boot entry.  We're using this CPUs
>> @@ -325,9 +317,9 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
>>  	complete(&cpu_running);
>>  
>>  	/*
>> -	 * Setup the percpu timer for this CPU.
>> +	 * Setup the dummy broadcast timer for this CPU.
> To me, calling something a broadcast timer makes it sound like it performs the
> broadcast. We use the term "broadcast timer" elsewhere here (e.g.
> broadcast_timer_setup), and I think it's any unnecessarily confusing term.
>
> Might it be better to say "dummy timer" consistently?

Sure. I wonder if we need the comment at all. I can rename the function
to dummy_timer_setup() and it pretty much sounds like what the comment
will say.

>
> [...]
>
>> diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
>> index 2bdd4cf..c00a8f8 100644
>> --- a/arch/arm/mach-omap2/timer.c
>> +++ b/arch/arm/mach-omap2/timer.c
>> @@ -587,7 +587,6 @@ OMAP_SYS_GP_TIMER_INIT(3_am33xx, 1, OMAP4_MPU_SOURCE, "ti,timer-alwon",
>>  #ifdef CONFIG_ARCH_OMAP4
>>  OMAP_SYS_32K_TIMER_INIT(4, 1, OMAP4_32K_SOURCE, "ti,timer-alwon",
>>  			2, OMAP4_MPU_SOURCE);
>> -#ifdef CONFIG_LOCAL_TIMERS
>>  static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, OMAP44XX_LOCAL_TWD_BASE, 29);
>>  void __init omap4_local_timer_init(void)
>>  {
>> @@ -606,12 +605,6 @@ void __init omap4_local_timer_init(void)
>>  			pr_err("twd_local_timer_register failed %d\n", err);
>>  	}
>>  }
>> -#else /* CONFIG_LOCAL_TIMERS */
>> -void __init omap4_local_timer_init(void)
>> -{
>> -	omap4_sync32k_timer_init();
>> -}
>> -#endif /* CONFIG_LOCAL_TIMERS */
>>  #endif /* CONFIG_ARCH_OMAP4 */
>>  
>>  #ifdef CONFIG_SOC_OMAP5
> I believe the above OMAP changes should have been in an earlier patch?

There isn't an omap patch. I could make it part of the smp_twd patch?

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH 8/8] ARM: smp: Remove local timer API
  2013-02-22 16:25     ` Paul Mundt
@ 2013-02-25 13:40       ` Mark Rutland
  2013-03-04 23:50         ` Stephen Boyd
  0 siblings, 1 reply; 19+ messages in thread
From: Mark Rutland @ 2013-02-25 13:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Feb 22, 2013 at 04:25:00PM +0000, Paul Mundt wrote:
> On Fri, Feb 22, 2013 at 11:15:45AM +0000, Mark Rutland wrote:
> > One thing that struck me when I was fiddling with the broadcast mechanism was
> > that it should be possible to have a generic dummy timer implementation. As
> > long as the architecture calls notifiers at the appropriate times, it should
> > look like any other timer driver (apart from not touching any hardware). It just
> > needs to depend on ARCH_HAS_TICK_BROADCAST.
> > 
> > I believe it shouldn't be too difficult to implement, though I may be blind to
> > some problems.
> > 
> It would be nice to have a generic dummy timer driver, quite a few
> architectures could use it directly already. If no one beats me to it,
> I'll give it a go as I convert the SH stuff over to using
> ARCH_HAS_TICK_BROADCAST and killing off the local timer API there.
> 

I've had a quick go at writing a generic timer driver. I've not had a chance to
test it, and there are a couple of things that are up for discussion (e.g. what
should the rating be) but I think we want something very close to this.

Thanks,
Mark.

---->8----

>From 1ca7fdf68fbb9b026237803db8c55a34b4f2cfa2 Mon Sep 17 00:00:00 2001
From: Mark Rutland <mark.rutland@arm.com>
Date: Sun, 24 Feb 2013 22:31:24 +0000
Subject: [PATCH] clocksource: add generic dummy timer driver

Several architectures have a dummy timer driver tightly coupled with
their broadcast code to support machines without cpu-local timers (or
where there is a lack of driver support).

Since 12ad100046: "clockevents: Add generic timer broadcast function"
it's been possible to write broadcast-capable timer drivers decoupled
from the broadcast mechanism. We can use this functionality to implement
a generic dummy timer driver that can be shared by all architectures
with generic tick broadcast (ARCH_HAS_TICK_BROADCAST).

This patch implements a generic dummy timer using this facility.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
---
 drivers/clocksource/Makefile      |  1 +
 drivers/clocksource/dummy_timer.c | 67 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+)
 create mode 100644 drivers/clocksource/dummy_timer.c

diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 7d671b8..8f2b13f 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -21,3 +21,4 @@ obj-$(CONFIG_ARCH_TEGRA)	+= tegra20_timer.o
 obj-$(CONFIG_VT8500_TIMER)	+= vt8500_timer.o
 
 obj-$(CONFIG_ARM_ARCH_TIMER)		+= arm_arch_timer.o
+obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST)	+= dummy_timer.o
diff --git a/drivers/clocksource/dummy_timer.c b/drivers/clocksource/dummy_timer.c
new file mode 100644
index 0000000..bdaba34
--- /dev/null
+++ b/drivers/clocksource/dummy_timer.c
@@ -0,0 +1,67 @@
+/*
+ *  linux/drivers/clocksource/dummy_timer.c
+ *
+ *  Copyright (C) 2013 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/clockchips.h>
+#include <linux/cpu.h>
+#include <linux/init.h>
+#include <linux/percpu.h>
+
+DEFINE_PER_CPU(struct clock_event_device, dummy_evt);
+
+static void dummy_set_mode(enum clock_event_mode mode,
+			   struct clock_event_device *evt)
+{
+	/*
+	 * Core clockevents code will call this when exchanging timer devices.
+	 * We don't need to do anything here.
+	 */
+}
+
+static void __cpuinit dummy_setup(void)
+{
+	int cpu = smp_processor_id();
+	struct clock_event_device *evt = &per_cpu(dummy_evt, cpu);
+
+	evt->name	= "dummy timer";
+	evt->features	= CLOCK_EVT_FEAT_PERIODIC |
+			  CLOCK_EVT_FEAT_ONESHOT |
+			  CLOCK_EVT_FEAT_DUMMY;
+	evt->rating	= 100;
+	evt->set_mode	= dummy_set_mode;
+	evt->cpumask	= cpumask_of(cpu);
+
+	clockevents_register_device(evt);
+}
+
+static int __cpuinit dummy_cpu_notify(struct notifier_block *self,
+				      unsigned long action, void *hcpu)
+{
+	if ((action & ~CPU_TASKS_FROZEN) == CPU_STARTING)
+		dummy_setup();
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block dummy_cpu_nb __cpuinitdata = {
+	.notifier_call = dummy_cpu_notify,
+};
+
+static int __init dummy_register(void)
+{
+	int err = register_cpu_notifier(&dummy_cpu_nb);
+	if (err)
+		return err;
+
+	/* We won't get a call on the boot CPU, so register immediately */
+	dummy_setup();
+
+	return 0;
+}
+device_initcall(dummy_register);
-- 
1.8.1.1

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

* [PATCH 8/8] ARM: smp: Remove local timer API
  2013-02-24  2:37     ` Stephen Boyd
@ 2013-02-25 13:44       ` Mark Rutland
  0 siblings, 0 replies; 19+ messages in thread
From: Mark Rutland @ 2013-02-25 13:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Feb 24, 2013 at 02:37:15AM +0000, Stephen Boyd wrote:
> On 2/22/2013 3:15 AM, Mark Rutland wrote:
> > Hi Stephen,
> >
> > One thing that struck me when I was fiddling with the broadcast mechanism was
> > that it should be possible to have a generic dummy timer implementation. As
> > long as the architecture calls notifiers at the appropriate times, it should
> > look like any other timer driver (apart from not touching any hardware). It just
> > needs to depend on ARCH_HAS_TICK_BROADCAST.
> >
> > I believe it shouldn't be too difficult to implement, though I may be blind to
> > some problems.
> 
> I completely agree and I was thinking the same thing while writing this
> patchset.

Great! I've just sent a first attempt in another subthread [1].

[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2013-February/151539.html

[...]

> >> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> >> index dedf02b..7d4338d 100644
> >> --- a/arch/arm/Kconfig
> >> +++ b/arch/arm/Kconfig
> >> @@ -1527,6 +1527,7 @@ config SMP
> >>  	depends on HAVE_SMP
> >>  	depends on MMU
> >>  	select HAVE_ARM_SCU if !ARCH_MSM_SCORPIONMP
> >> +	select HAVE_ARM_TWD if (!ARCH_MSM_SCORPIONMP && !EXYNOS4_MCT)
> >>  	select USE_GENERIC_SMP_HELPERS
> >>  	help
> >>  	  This enables support for systems with more than one CPU. If you have
> > Should this have been in an earlier patch?
> 
> It could be part of the smp_twd patch if you like.

I think it'd be better placed there.

> 
> > Why is it necessary?
> 
> It shouldn't be. In fact, I sent a patchset a few months ago that pushed
> down the TWD and SCU selects to the respective machines that need them.
> I should resend that.

That would be even better.

> 
> >
> > [...]
> >
> >> -static void percpu_timer_setup(void);
> >> +static void broadcast_timer_setup(void);
> >>  
> >>  /*
> >>   * This is the secondary CPU boot entry.  We're using this CPUs
> >> @@ -325,9 +317,9 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
> >>  	complete(&cpu_running);
> >>  
> >>  	/*
> >> -	 * Setup the percpu timer for this CPU.
> >> +	 * Setup the dummy broadcast timer for this CPU.
> > To me, calling something a broadcast timer makes it sound like it performs the
> > broadcast. We use the term "broadcast timer" elsewhere here (e.g.
> > broadcast_timer_setup), and I think it's any unnecessarily confusing term.
> >
> > Might it be better to say "dummy timer" consistently?
> 
> Sure. I wonder if we need the comment at all. I can rename the function
> to dummy_timer_setup() and it pretty much sounds like what the comment
> will say.

Sounds good to me, unless we try to fold the generic dummy driver into this
series.

> 
> >
> > [...]
> >
> >> diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
> >> index 2bdd4cf..c00a8f8 100644
> >> --- a/arch/arm/mach-omap2/timer.c
> >> +++ b/arch/arm/mach-omap2/timer.c
> >> @@ -587,7 +587,6 @@ OMAP_SYS_GP_TIMER_INIT(3_am33xx, 1, OMAP4_MPU_SOURCE, "ti,timer-alwon",
> >>  #ifdef CONFIG_ARCH_OMAP4
> >>  OMAP_SYS_32K_TIMER_INIT(4, 1, OMAP4_32K_SOURCE, "ti,timer-alwon",
> >>  			2, OMAP4_MPU_SOURCE);
> >> -#ifdef CONFIG_LOCAL_TIMERS
> >>  static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, OMAP44XX_LOCAL_TWD_BASE, 29);
> >>  void __init omap4_local_timer_init(void)
> >>  {
> >> @@ -606,12 +605,6 @@ void __init omap4_local_timer_init(void)
> >>  			pr_err("twd_local_timer_register failed %d\n", err);
> >>  	}
> >>  }
> >> -#else /* CONFIG_LOCAL_TIMERS */
> >> -void __init omap4_local_timer_init(void)
> >> -{
> >> -	omap4_sync32k_timer_init();
> >> -}
> >> -#endif /* CONFIG_LOCAL_TIMERS */
> >>  #endif /* CONFIG_ARCH_OMAP4 */
> >>  
> >>  #ifdef CONFIG_SOC_OMAP5
> > I believe the above OMAP changes should have been in an earlier patch?
> 
> There isn't an omap patch. I could make it part of the smp_twd patch?

Sorry, I missed that while skimming the series. That might make more sense.
Possibly this could be its own patch?

Thanks,
Mark.

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

* [PATCH 8/8] ARM: smp: Remove local timer API
  2013-02-25 13:40       ` Mark Rutland
@ 2013-03-04 23:50         ` Stephen Boyd
  2013-03-04 23:52           ` Stephen Boyd
  2013-03-05 11:02           ` Mark Rutland
  0 siblings, 2 replies; 19+ messages in thread
From: Stephen Boyd @ 2013-03-04 23:50 UTC (permalink / raw)
  To: linux-arm-kernel

On 02/25/13 05:40, Mark Rutland wrote:
> I've had a quick go at writing a generic timer driver. I've not had a chance to
> test it, and there are a couple of things that are up for discussion (e.g. what
> should the rating be) but I think we want something very close to this.
>

This looks good to me. I only have some minor comments. What's the plan
for merging? Get tglx to take this and provide a stable branch and then
base my patches off that and get these patches taken through arm-soc?

> diff --git a/drivers/clocksource/dummy_timer.c b/drivers/clocksource/dummy_timer.c
> new file mode 100644
> index 0000000..bdaba34
> --- /dev/null
> +++ b/drivers/clocksource/dummy_timer.c
> @@ -0,0 +1,67 @@
> +/*
> + *  linux/drivers/clocksource/dummy_timer.c
> + *
> + *  Copyright (C) 2013 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/clockchips.h>
> +#include <linux/cpu.h>
> +#include <linux/init.h>
> +#include <linux/percpu.h>
> +
> +DEFINE_PER_CPU(struct clock_event_device, dummy_evt);

static?

> +
> +static void dummy_set_mode(enum clock_event_mode mode,
> +			   struct clock_event_device *evt)
> +{
> +	/*
> +	 * Core clockevents code will call this when exchanging timer devices.
> +	 * We don't need to do anything here.
> +	 */
> +}
> +
> +static void __cpuinit dummy_setup(void)
> +{
> +	int cpu = smp_processor_id();
> +	struct clock_event_device *evt = &per_cpu(dummy_evt, cpu);

Can we use __this_cpu_ptr()? I wonder if that makes the code generation
better or worse. I didn't do it in my 8/8 patch because I wanted the
code to be the same before and after to show code movement.

> +
> +	evt->name	= "dummy timer";
> +	evt->features	= CLOCK_EVT_FEAT_PERIODIC |
> +			  CLOCK_EVT_FEAT_ONESHOT |
> +			  CLOCK_EVT_FEAT_DUMMY;
> +	evt->rating	= 100;
> +	evt->set_mode	= dummy_set_mode;
> +	evt->cpumask	= cpumask_of(cpu);
> +
> +	clockevents_register_device(evt);
> +}
> +
> +static int __cpuinit dummy_cpu_notify(struct notifier_block *self,
> +				      unsigned long action, void *hcpu)
> +{
> +	if ((action & ~CPU_TASKS_FROZEN) == CPU_STARTING)
> +		dummy_setup();

There are already two dummy_setup() functions. Perhaps we can
s/dummy/dummy_broadcast/ throughout this file?

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH 8/8] ARM: smp: Remove local timer API
  2013-03-04 23:50         ` Stephen Boyd
@ 2013-03-04 23:52           ` Stephen Boyd
  2013-03-05 11:02           ` Mark Rutland
  1 sibling, 0 replies; 19+ messages in thread
From: Stephen Boyd @ 2013-03-04 23:52 UTC (permalink / raw)
  To: linux-arm-kernel

On 03/04/13 15:50, Stephen Boyd wrote:
>
>> +
>> +	evt->name	= "dummy timer";
>> +	evt->features	= CLOCK_EVT_FEAT_PERIODIC |
>> +			  CLOCK_EVT_FEAT_ONESHOT |
>> +			  CLOCK_EVT_FEAT_DUMMY;
>> +	evt->rating	= 100;
>> +	evt->set_mode	= dummy_set_mode;
>> +	evt->cpumask	= cpumask_of(cpu);
>> +
>> +	clockevents_register_device(evt);
>> +}
>> +
>> +static int __cpuinit dummy_cpu_notify(struct notifier_block *self,
>> +				      unsigned long action, void *hcpu)
>> +{
>> +	if ((action & ~CPU_TASKS_FROZEN) == CPU_STARTING)
>> +		dummy_setup();
> There are already two dummy_setup() functions. Perhaps we can
> s/dummy/dummy_broadcast/ throughout this file?
>

Sorry, meant to say dummy_timer not dummy_broadcast.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH 8/8] ARM: smp: Remove local timer API
  2013-03-04 23:50         ` Stephen Boyd
  2013-03-04 23:52           ` Stephen Boyd
@ 2013-03-05 11:02           ` Mark Rutland
  2013-03-05 18:45             ` Stephen Boyd
  1 sibling, 1 reply; 19+ messages in thread
From: Mark Rutland @ 2013-03-05 11:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Mar 04, 2013 at 11:50:22PM +0000, Stephen Boyd wrote:
> On 02/25/13 05:40, Mark Rutland wrote:
> > I've had a quick go at writing a generic timer driver. I've not had a chance to
> > test it, and there are a couple of things that are up for discussion (e.g. what
> > should the rating be) but I think we want something very close to this.
> >
> 
> This looks good to me. I only have some minor comments. What's the plan
> for merging? Get tglx to take this and provide a stable branch and then
> base my patches off that and get these patches taken through arm-soc?

Great.

That sounds about right, I don't really know what the best way would be.

> 
> > diff --git a/drivers/clocksource/dummy_timer.c b/drivers/clocksource/dummy_timer.c
> > new file mode 100644
> > index 0000000..bdaba34
> > --- /dev/null
> > +++ b/drivers/clocksource/dummy_timer.c
> > @@ -0,0 +1,67 @@
> > +/*
> > + *  linux/drivers/clocksource/dummy_timer.c
> > + *
> > + *  Copyright (C) 2013 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/clockchips.h>
> > +#include <linux/cpu.h>
> > +#include <linux/init.h>
> > +#include <linux/percpu.h>
> > +
> > +DEFINE_PER_CPU(struct clock_event_device, dummy_evt);
> 
> static?

Oops. Added.

> 
> > +
> > +static void dummy_set_mode(enum clock_event_mode mode,
> > +			   struct clock_event_device *evt)
> > +{
> > +	/*
> > +	 * Core clockevents code will call this when exchanging timer devices.
> > +	 * We don't need to do anything here.
> > +	 */
> > +}
> > +
> > +static void __cpuinit dummy_setup(void)
> > +{
> > +	int cpu = smp_processor_id();
> > +	struct clock_event_device *evt = &per_cpu(dummy_evt, cpu);
> 
> Can we use __this_cpu_ptr()? I wonder if that makes the code generation
> better or worse. I didn't do it in my 8/8 patch because I wanted the
> code to be the same before and after to show code movement.

I did that originally, but thought as I needed the cpu value for the mask
anyway that there wasn't much point. I'm not that good at reading generated
assembly, so I can't really say if either's better.

> 
> > +
> > +	evt->name	= "dummy timer";
> > +	evt->features	= CLOCK_EVT_FEAT_PERIODIC |
> > +			  CLOCK_EVT_FEAT_ONESHOT |
> > +			  CLOCK_EVT_FEAT_DUMMY;
> > +	evt->rating	= 100;
> > +	evt->set_mode	= dummy_set_mode;
> > +	evt->cpumask	= cpumask_of(cpu);
> > +
> > +	clockevents_register_device(evt);
> > +}
> > +
> > +static int __cpuinit dummy_cpu_notify(struct notifier_block *self,
> > +				      unsigned long action, void *hcpu)
> > +{
> > +	if ((action & ~CPU_TASKS_FROZEN) == CPU_STARTING)
> > +		dummy_setup();
> 
> There are already two dummy_setup() functions. Perhaps we can
> s/dummy/dummy_broadcast/ throughout this file?

I've done s/dummy/dummy_timer/ as suggested in your other reply.

Thanks,
Mark.

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

* [PATCH 8/8] ARM: smp: Remove local timer API
  2013-03-05 11:02           ` Mark Rutland
@ 2013-03-05 18:45             ` Stephen Boyd
  0 siblings, 0 replies; 19+ messages in thread
From: Stephen Boyd @ 2013-03-05 18:45 UTC (permalink / raw)
  To: linux-arm-kernel

On 03/05/13 03:02, Mark Rutland wrote:
>
>>> +
>>> +static void dummy_set_mode(enum clock_event_mode mode,
>>> +			   struct clock_event_device *evt)
>>> +{
>>> +	/*
>>> +	 * Core clockevents code will call this when exchanging timer devices.
>>> +	 * We don't need to do anything here.
>>> +	 */
>>> +}
>>> +
>>> +static void __cpuinit dummy_setup(void)
>>> +{
>>> +	int cpu = smp_processor_id();
>>> +	struct clock_event_device *evt = &per_cpu(dummy_evt, cpu);
>> Can we use __this_cpu_ptr()? I wonder if that makes the code generation
>> better or worse. I didn't do it in my 8/8 patch because I wanted the
>> code to be the same before and after to show code movement.
> I did that originally, but thought as I needed the cpu value for the mask
> anyway that there wasn't much point. I'm not that good at reading generated
> assembly, so I can't really say if either's better.

It looks to be two instructions shorter.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH 5/8] ARM: MSM: Divorce msm_timer from local timer API
  2013-02-22  7:27 ` [PATCH 5/8] ARM: MSM: Divorce msm_timer " Stephen Boyd
@ 2013-03-05 19:04   ` David Brown
  0 siblings, 0 replies; 19+ messages in thread
From: David Brown @ 2013-03-05 19:04 UTC (permalink / raw)
  To: linux-arm-kernel

Stephen Boyd <sboyd@codeaurora.org> writes:

> Separate the msm_timer from the local timer API. This will allow
> us to remove ARM local timer support in the near future and gets
> us closer to moving this driver to drivers/clocksource.
>
> Cc: David Brown <davidb@codeaurora.org>
> Cc: Daniel Walker <dwalker@fifo99.com>
> Cc: Bryan Huntsman <bryanh@codeaurora.org>
> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> ---
>  arch/arm/mach-msm/timer.c | 125 +++++++++++++++++++++++++---------------------

Acked-by: David Brown <davidb@codeaurora.org>

-- 
sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

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

end of thread, other threads:[~2013-03-05 19:04 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-02-22  7:27 [PATCH 0/8] Remove ARM local timer API Stephen Boyd
2013-02-22  7:27 ` [PATCH 1/8] ARM: smp: Lower rating of dummy broadcast device Stephen Boyd
2013-02-22  7:27 ` [PATCH 2/8] ARM: smp_twd: Divorce smp_twd from local timer API Stephen Boyd
2013-02-22  7:27 ` [PATCH 3/8] ARM: EXYNOS4: Divorce mct " Stephen Boyd
2013-02-22  7:27 ` [PATCH 4/8] ARM: PRIMA2: Divorce timer-marco " Stephen Boyd
2013-02-22  7:27 ` [PATCH 5/8] ARM: MSM: Divorce msm_timer " Stephen Boyd
2013-03-05 19:04   ` David Brown
2013-02-22  7:27 ` [PATCH 6/8] clocksource: time-armada-370-xp: Fix sparse warning Stephen Boyd
2013-02-22  7:27 ` [PATCH 7/8] clocksource: time-armada-370-xp: Divorce from local timer API Stephen Boyd
2013-02-22  7:27 ` [PATCH 8/8] ARM: smp: Remove " Stephen Boyd
2013-02-22 11:15   ` Mark Rutland
2013-02-22 16:25     ` Paul Mundt
2013-02-25 13:40       ` Mark Rutland
2013-03-04 23:50         ` Stephen Boyd
2013-03-04 23:52           ` Stephen Boyd
2013-03-05 11:02           ` Mark Rutland
2013-03-05 18:45             ` Stephen Boyd
2013-02-24  2:37     ` Stephen Boyd
2013-02-25 13:44       ` Mark Rutland

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).