2013-04-08 21:27:42

by Stephen Boyd

[permalink] [raw]
Subject: [PATCHv4 00/11] Remove ARM local timer API

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 v3.9-rc5. I'm still looking for Acks/Tested-by
on EXYNOS and PRIMA2.

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

Changes since v3:
* New patch to fix SMP with dummy timers registered after a global timer
* Push this_cpu_ptr lower to avoid preemptible false positive warnings
* Collected acks/tested-bys

Changes since v2:
* Bug fixes in smp_twd from Tony Lindgren's testing
* Move smp_twd to use late_time_init hook
* Collected Acks

Changes since v1:
* Picked up Mark's generic dummy timer driver
* Split out omap changes into new patch

Mark Rutland (1):
clocksource: add generic dummy timer driver

Stephen Boyd (10):
clockevents: Prefer CPU local devices over global devices
ARM: smp: Remove duplicate dummy timer implementation
ARM: smp_twd: Divorce smp_twd from local timer API
ARM: OMAP2+: Divorce 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 | 87 ---------------------
arch/arm/kernel/smp_twd.c | 64 +++++++++++-----
arch/arm/mach-exynos/mct.c | 60 ++++++++++-----
arch/arm/mach-msm/timer.c | 127 +++++++++++++++++--------------
arch/arm/mach-omap2/Kconfig | 1 -
arch/arm/mach-omap2/timer.c | 7 --
arch/arm/mach-prima2/timer-marco.c | 100 +++++++++++++-----------
drivers/clocksource/Makefile | 1 +
drivers/clocksource/dummy_timer.c | 69 +++++++++++++++++
drivers/clocksource/time-armada-370-xp.c | 92 +++++++++++-----------
include/linux/time-armada-370-xp.h | 4 +-
kernel/time/tick-common.c | 5 +-
14 files changed, 327 insertions(+), 336 deletions(-)
delete mode 100644 arch/arm/include/asm/localtimer.h
create mode 100644 drivers/clocksource/dummy_timer.c

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


2013-04-08 21:27:44

by Stephen Boyd

[permalink] [raw]
Subject: [PATCHv4 09/11] clocksource: time-armada-370-xp: Fix sparse warning

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 along with the init.h include.

Acked-by: Gregory CLEMENT <[email protected]>
Signed-off-by: Stephen Boyd <[email protected]>
---
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

2013-04-08 21:27:43

by Stephen Boyd

[permalink] [raw]
Subject: [PATCHv4 06/11] ARM: EXYNOS4: Divorce mct from local timer API

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 <[email protected]>
Signed-off-by: Stephen Boyd <[email protected]>
---
arch/arm/mach-exynos/mct.c | 60 +++++++++++++++++++++++++++++++++-------------
1 file changed, 43 insertions(+), 17 deletions(-)

diff --git a/arch/arm/mach-exynos/mct.c b/arch/arm/mach-exynos/mct.c
index c9d6650..a3ec5b6 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);

@@ -387,8 +385,7 @@ static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt)
unsigned int cpu = smp_processor_id();
int mct_lx_irq;

- mevt = this_cpu_ptr(&percpu_mct_tick);
- mevt->evt = evt;
+ mevt = container_of(evt, struct mct_clock_event_device, 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,43 @@ 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;
+
+ /*
+ * Dereference cpu pointer in each case to avoid spurious
+ * preemptible warnings
+ */
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_STARTING:
+ mevt = this_cpu_ptr(&percpu_mct_tick);
+ exynos4_local_timer_setup(&mevt->evt);
+ break;
+ case CPU_DYING:
+ mevt = this_cpu_ptr(&percpu_mct_tick);
+ exynos4_local_timer_stop(&mevt->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 +481,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

2013-04-08 21:27:41

by Stephen Boyd

[permalink] [raw]
Subject: [PATCHv4 01/11] clockevents: Prefer CPU local devices over global devices

On an SMP system with only one global clockevent and a dummy
clockevent per CPU we run into problems. We want the dummy
clockevents to be registered as the per CPU tick devices, but
we can only achieve that if we register the dummy clockevents
before the global clockevent or if we artificially inflate the
rating of the dummy clockevents to be higher than the rating
of the global clockevent. Failure to do so leads to boot
hangs when the dummy timers are registered on all other CPUs
besides the CPU that accepted the global clockevent as its tick
device and there is no broadcast timer to poke the dummy
devices.

If we're registering multiple clockevents and one clockevent is
global and the other is local to a particular CPU we should
choose to use the local clockevent regardless of the rating of
the device. This way, if the clockevent is a dummy it will take
the tick device duty as long as there isn't a higher rated tick
device and any global clockevent will be bumped out into
broadcast mode, fixing the problem described above.

Reported-by: Mark Rutland <[email protected]>
Cc: John Stultz <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Signed-off-by: Stephen Boyd <[email protected]>
---
kernel/time/tick-common.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
index b1600a6..9ea59b9 100644
--- a/kernel/time/tick-common.c
+++ b/kernel/time/tick-common.c
@@ -251,9 +251,10 @@ static int tick_check_new_device(struct clock_event_device *newdev)
!(newdev->features & CLOCK_EVT_FEAT_ONESHOT))
goto out_bc;
/*
- * Check the rating
+ * Check the rating, but prefer CPU local devices
*/
- if (curdev->rating >= newdev->rating)
+ if (curdev->rating >= newdev->rating &&
+ cpumask_equal(curdev->cpumask, newdev->cpumask))
goto out_bc;
}

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

2013-04-08 21:28:41

by Stephen Boyd

[permalink] [raw]
Subject: [PATCHv4 10/11] clocksource: time-armada-370-xp: Divorce from local timer API

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.

Acked-by: Gregory CLEMENT <[email protected]>
Tested-by: Gregory CLEMENT <[email protected]>
Signed-off-by: Stephen Boyd <[email protected]>
---
drivers/clocksource/time-armada-370-xp.c | 89 +++++++++++++++-----------------
1 file changed, 41 insertions(+), 48 deletions(-)

diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c
index efe4aef..8e6296d 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,21 +143,14 @@ 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)
{
/*
* ACK timer interrupt and call event handler.
*/
- struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
+ struct clock_event_device *evt = dev_id;

writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
evt->event_handler(evt);
@@ -173,42 +166,55 @@ 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)
+{
+ /*
+ * Dereference cpu pointer in each case to avoid spurious
+ * preemptible warnings
+ */
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_STARTING:
+ armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt));
+ break;
+ case CPU_DYING:
+ armada_370_xp_timer_stop(this_cpu_ptr(armada_370_xp_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 +230,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 +239,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 +252,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 +277,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

2013-04-08 21:29:05

by Stephen Boyd

[permalink] [raw]
Subject: [PATCHv4 11/11] ARM: smp: Remove local timer API

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

Cc: Russell King <[email protected]>
Acked-by: Tony Lindgren <[email protected]>
Signed-off-by: Stephen Boyd <[email protected]>
---
arch/arm/Kconfig | 10 ------
arch/arm/include/asm/localtimer.h | 34 -------------------
arch/arm/kernel/smp.c | 69 ---------------------------------------
3 files changed, 113 deletions(-)
delete mode 100644 arch/arm/include/asm/localtimer.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index ee6bb9d..f97a980 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1643,16 +1643,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
- 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.
-
# The GPIO number here must be sorted by descending number. In case of
# a multiplatform kernel, we just want the highest value required by the
# selected platforms.
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 4de4d14..4c49138 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,8 +261,6 @@ static void __cpuinit smp_store_cpu_info(unsigned int cpuid)
store_cpu_topology(cpuid);
}

-static void percpu_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.
@@ -325,11 +315,6 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
set_cpu_online(cpu, true);
complete(&cpu_running);

- /*
- * Setup the percpu timer for this CPU.
- */
- percpu_timer_setup();
-
local_irq_enable();
local_fiq_enable();

@@ -376,12 +361,6 @@ 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.
- */
- percpu_timer_setup();
-
- /*
* Initialise the present map, which describes the set of CPUs
* actually populated at the present time. A platform should
* re-initialize the map in the platforms smp_prepare_cpus()
@@ -457,11 +436,6 @@ u64 smp_irq_stat_cpu(unsigned int cpu)
return sum;
}

-/*
- * Timer (local or broadcast) support
- */
-static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent);
-
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
void tick_broadcast(const struct cpumask *mask)
{
@@ -469,49 +443,6 @@ void tick_broadcast(const struct cpumask *mask)
}
#endif

-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);
-}
-
-#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);

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

2013-04-08 21:29:04

by Stephen Boyd

[permalink] [raw]
Subject: [PATCHv4 05/11] ARM: OMAP2+: Divorce from local timer API

Now that the TWD doesn't rely on the local timer API, OMAP can
stop selecting it in Kconfig and relying on the config option to
decide if it should call smp_twd functions.

Acked-by: Santosh Shilimkar <[email protected]>
Acked-by: Tony Lindgren <[email protected]>
Signed-off-by: Stephen Boyd <[email protected]>
---
arch/arm/mach-omap2/Kconfig | 1 -
arch/arm/mach-omap2/timer.c | 7 -------
2 files changed, 8 deletions(-)

diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 8111cd9..1b731e3 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

2013-04-08 21:29:01

by Stephen Boyd

[permalink] [raw]
Subject: [PATCHv4 07/11] ARM: PRIMA2: Divorce timer-marco from local timer API

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 <[email protected]>
Signed-off-by: Stephen Boyd <[email protected]>
---
arch/arm/mach-prima2/timer-marco.c | 100 ++++++++++++++++++++-----------------
1 file changed, 54 insertions(+), 46 deletions(-)

diff --git a/arch/arm/mach-prima2/timer-marco.c b/arch/arm/mach-prima2/timer-marco.c
index f4eea2e..123c89a 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,77 @@ 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 struct local_timer_ops sirfsoc_local_timer_ops __cpuinitdata = {
- .setup = sirfsoc_local_timer_setup,
- .stop = sirfsoc_local_timer_stop,
+static int __cpuinit sirfsoc_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ /*
+ * Dereference cpu pointer in each case to avoid spurious
+ * preemptible warnings
+ */
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_STARTING:
+ sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent));
+ break;
+ case CPU_DYING:
+ sirfsoc_local_timer_stop(this_cpu_ptr(sirfsoc_clockevent));
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+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 +293,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 +316,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

2013-04-08 21:29:00

by Stephen Boyd

[permalink] [raw]
Subject: [PATCHv4 08/11] ARM: msm: Divorce msm_timer from local timer API

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.

Acked-by: David Brown <[email protected]>
Cc: Daniel Walker <[email protected]>
Cc: Bryan Huntsman <[email protected]>
Signed-off-by: Stephen Boyd <[email protected]>
---
arch/arm/mach-msm/timer.c | 127 +++++++++++++++++++++++++---------------------
1 file changed, 69 insertions(+), 58 deletions(-)

diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 2969027..f4bc4a6 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,68 @@ 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)
+{
+ /*
+ * Dereference cpu pointer in each case to avoid spurious
+ * preemptible warnings
+ */
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_STARTING:
+ msm_local_timer_setup(this_cpu_ptr(msm_evt));
+ break;
+ case CPU_DYING:
+ msm_local_timer_stop(this_cpu_ptr(msm_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 +187,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

2013-04-08 21:30:46

by Stephen Boyd

[permalink] [raw]
Subject: [PATCHv4 04/11] ARM: smp_twd: Divorce smp_twd from local timer API

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 <[email protected]>
Cc: Tony Lindgren <[email protected]>
Tested-by: Mark Rutland <[email protected]>
Signed-off-by: Stephen Boyd <[email protected]>
---
arch/arm/Kconfig | 2 +-
arch/arm/kernel/smp_twd.c | 64 +++++++++++++++++++++++++++++++----------------
2 files changed, 44 insertions(+), 22 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 13b7394..ee6bb9d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1523,6 +1523,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,7 +1647,6 @@ 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
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 3f25650..a79476d 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>
@@ -24,7 +25,6 @@

#include <asm/smp_plat.h>
#include <asm/smp_twd.h>
-#include <asm/localtimer.h>

/* set up by the platform code */
static void __iomem *twd_base;
@@ -33,7 +33,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,
@@ -90,8 +90,10 @@ static int twd_timer_ack(void)
return 0;
}

-static void twd_timer_stop(struct clock_event_device *clk)
+static void twd_timer_stop(void)
{
+ struct clock_event_device *clk = __this_cpu_ptr(twd_evt);
+
twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
disable_percpu_irq(clk->irq);
}
@@ -106,7 +108,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,
@@ -132,7 +134,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;
@@ -151,7 +153,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,
@@ -177,7 +179,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);

@@ -228,7 +230,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);
@@ -265,9 +267,9 @@ static void twd_get_clock(struct device_node *np)
/*
* Setup the local clock events for a CPU.
*/
-static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
+static void __cpuinit twd_timer_setup(void)
{
- struct clock_event_device **this_cpu_clk;
+ struct clock_event_device *clk = __this_cpu_ptr(twd_evt);
int cpu = smp_processor_id();

/*
@@ -276,9 +278,9 @@ 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(clk);
enable_percpu_irq(clk->irq, 0);
- return 0;
+ return;
}
per_cpu(percpu_setup_called, cpu) = true;

@@ -297,27 +299,37 @@ 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);
enable_percpu_irq(clk->irq, 0);
+}

- return 0;
+static int __cpuinit twd_timer_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_STARTING:
+ twd_timer_setup();
+ break;
+ case CPU_DYING:
+ twd_timer_stop();
+ break;
+ }
+
+ return NOTIFY_OK;
}

-static struct local_timer_ops twd_lt_ops __cpuinitdata = {
- .setup = twd_timer_setup,
- .stop = twd_timer_stop,
+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;
@@ -329,12 +341,22 @@ 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;

twd_get_clock(np);

+ /*
+ * Immediately configure the timer on the boot CPU, unless we need
+ * jiffies to be incrementing to calibrate the rate in which case
+ * setup the timer in late_time_init.
+ */
+ if (twd_timer_rate)
+ twd_timer_setup();
+ else
+ late_time_init = twd_timer_setup;
+
return 0;

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

2013-04-08 21:30:44

by Stephen Boyd

[permalink] [raw]
Subject: [PATCHv4 02/11] clocksource: add generic dummy timer driver

From: Mark Rutland <[email protected]>

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 <[email protected]>
Cc: John Stultz <[email protected]>
Cc: Thomas Gleixner <[email protected]>
[sboyd: Make percpu data static, use __this_cpu_ptr(), move to
early_initcall to properly register on each CPU, only
register if more than one CPU possible]
Signed-off-by: Stephen Boyd <[email protected]>
---
drivers/clocksource/Makefile | 1 +
drivers/clocksource/dummy_timer.c | 69 +++++++++++++++++++++++++++++++++++++++
2 files changed, 70 insertions(+)
create mode 100644 drivers/clocksource/dummy_timer.c

diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 4d8283a..655d718 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o

obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.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..1f55f96
--- /dev/null
+++ b/drivers/clocksource/dummy_timer.c
@@ -0,0 +1,69 @@
+/*
+ * 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>
+#include <linux/cpumask.h>
+
+static DEFINE_PER_CPU(struct clock_event_device, dummy_timer_evt);
+
+static void dummy_timer_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_timer_setup(void)
+{
+ int cpu = smp_processor_id();
+ struct clock_event_device *evt = __this_cpu_ptr(&dummy_timer_evt);
+
+ 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_timer_set_mode;
+ evt->cpumask = cpumask_of(cpu);
+
+ clockevents_register_device(evt);
+}
+
+static int __cpuinit dummy_timer_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ if ((action & ~CPU_TASKS_FROZEN) == CPU_STARTING)
+ dummy_timer_setup();
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block dummy_timer_cpu_nb __cpuinitdata = {
+ .notifier_call = dummy_timer_cpu_notify,
+};
+
+static int __init dummy_timer_register(void)
+{
+ int err = register_cpu_notifier(&dummy_timer_cpu_nb);
+ if (err)
+ return err;
+
+ /* We won't get a call on the boot CPU, so register immediately */
+ if (num_possible_cpus() > 1)
+ dummy_timer_setup();
+
+ return 0;
+}
+early_initcall(dummy_timer_register);
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

2013-04-08 21:30:43

by Stephen Boyd

[permalink] [raw]
Subject: [PATCHv4 03/11] ARM: smp: Remove duplicate dummy timer implementation

Drop ARM's version of the dummy timer now that we have a generic
implementation in drivers/clocksource.

Cc: Russell King <[email protected]>
Signed-off-by: Stephen Boyd <[email protected]>
---
arch/arm/kernel/smp.c | 22 ++--------------------
1 file changed, 2 insertions(+), 20 deletions(-)

diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 79078ed..4de4d14 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -469,24 +469,6 @@ void tick_broadcast(const struct cpumask *mask)
}
#endif

-static void broadcast_timer_set_mode(enum clock_event_mode mode,
- struct clock_event_device *evt)
-{
-}
-
-static void __cpuinit broadcast_timer_setup(struct clock_event_device *evt)
-{
- evt->name = "dummy_timer";
- evt->features = CLOCK_EVT_FEAT_ONESHOT |
- CLOCK_EVT_FEAT_PERIODIC |
- CLOCK_EVT_FEAT_DUMMY;
- evt->rating = 100;
- evt->mult = 1;
- evt->set_mode = broadcast_timer_set_mode;
-
- clockevents_register_device(evt);
-}
-
static struct local_timer_ops *lt_ops;

#ifdef CONFIG_LOCAL_TIMERS
@@ -510,8 +492,8 @@ static void __cpuinit percpu_timer_setup(void)

evt->cpumask = cpumask_of(cpu);

- if (!lt_ops || lt_ops->setup(evt))
- broadcast_timer_setup(evt);
+ if (lt_ops)
+ lt_ops->setup(evt);
}

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

2013-04-09 10:33:20

by Mark Rutland

[permalink] [raw]
Subject: Re: [PATCHv4 01/11] clockevents: Prefer CPU local devices over global devices

Hi Stephen,

Apologies for my lack of response on the last version of this.

On Mon, Apr 08, 2013 at 10:27:23PM +0100, Stephen Boyd wrote:
> On an SMP system with only one global clockevent and a dummy
> clockevent per CPU we run into problems. We want the dummy
> clockevents to be registered as the per CPU tick devices, but
> we can only achieve that if we register the dummy clockevents
> before the global clockevent or if we artificially inflate the
> rating of the dummy clockevents to be higher than the rating
> of the global clockevent. Failure to do so leads to boot
> hangs when the dummy timers are registered on all other CPUs
> besides the CPU that accepted the global clockevent as its tick
> device and there is no broadcast timer to poke the dummy
> devices.
>
> If we're registering multiple clockevents and one clockevent is
> global and the other is local to a particular CPU we should
> choose to use the local clockevent regardless of the rating of
> the device. This way, if the clockevent is a dummy it will take
> the tick device duty as long as there isn't a higher rated tick
> device and any global clockevent will be bumped out into
> broadcast mode, fixing the problem described above.

It might be worth pointing out that if dummy timers are only registered
when there's more than one CPU, UP behaviour won't degrade from the
current state of affairs.

>
> Reported-by: Mark Rutland <[email protected]>
> Cc: John Stultz <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> Signed-off-by: Stephen Boyd <[email protected]>
> ---
> kernel/time/tick-common.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
> index b1600a6..9ea59b9 100644
> --- a/kernel/time/tick-common.c
> +++ b/kernel/time/tick-common.c
> @@ -251,9 +251,10 @@ static int tick_check_new_device(struct clock_event_device *newdev)
> !(newdev->features & CLOCK_EVT_FEAT_ONESHOT))
> goto out_bc;
> /*
> - * Check the rating
> + * Check the rating, but prefer CPU local devices
> */
> - if (curdev->rating >= newdev->rating)
> + if (curdev->rating >= newdev->rating &&
> + cpumask_equal(curdev->cpumask, newdev->cpumask))
> goto out_bc;
> }

This looks good to me. I tested this on a TC2 with a v3.9-rc6 kernel
without architected timer support. The patch restores the ability to use
the sp804 as a broadcast source.

Tested-by: Mark Rutland <[email protected]>

If possible I think this should sit in -next for a bit to make sure it
doesn't have any unexpected side effects.

Otherwise, results of testing below.

Without this patch (where boot hangs), magic sysrq show-all-timers give
me the following:

Tick Device: mode: 1
Broadcast device
Clock Event Device: <NULL>
tick_broadcast_mask: 0000000e
tick_broadcast_oneshot_mask: 00000000


Tick Device: mode: 1
Per CPU device: 0
Clock Event Device: v2m-timer0
max_delta_ns: 4294966591000
min_delta_ns: 14999
mult: 2147484
shift: 31
mode: 3
next_event: 18340000000 nsecs
set_next_event: sp804_set_next_event
set_mode: sp804_set_mode
event_handler: hrtimer_interrupt
retries: 0

Tick Device: mode: 0
Per CPU device: 1
Clock Event Device: dummy_timer
max_delta_ns: 0
min_delta_ns: 0
mult: 1
shift: 0
mode: 1
next_event: 9223372036854775807 nsecs
set_next_event: <00000000>
set_mode: broadcast_timer_set_mode
event_handler: tick_handle_periodic
retries: 0

[...]

With this patch (where boot succeeds), show-all-timers gives me the following:

Tick Device: mode: 0
Broadcast device
Clock Event Device: v2m-timer0
max_delta_ns: 4294966591000
min_delta_ns: 14999
mult: 2147484
shift: 31
mode: 2
next_event: 9223372036854775807 nsecs
set_next_event: sp804_set_next_event
set_mode: sp804_set_mode
event_handler: tick_handle_periodic_broadcast
retries: 0
tick_broadcast_mask: 0000000f
tick_broadcast_oneshot_mask: 00000000


Tick Device: mode: 0
Per CPU device: 0
Clock Event Device: dummy_timer
max_delta_ns: 0
min_delta_ns: 0
mult: 1
shift: 0
mode: 1
next_event: 9223372036854775807 nsecs
set_next_event: <pK-error>
set_mode: broadcast_timer_set_mode
event_handler: tick_handle_periodic
retries: 0

Tick Device: mode: 0
Per CPU device: 1
Clock Event Device: dummy_timer
max_delta_ns: 0
min_delta_ns: 0
mult: 1
shift: 0
mode: 1
next_event: 9223372036854775807 nsecs
set_next_event: <pK-error>
set_mode: broadcast_timer_set_mode
event_handler: tick_handle_periodic
retries: 0

[...]

Cheers,
Mark.

2013-04-09 16:49:29

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCHv4 01/11] clockevents: Prefer CPU local devices over global devices

On 04/09/13 03:33, Mark Rutland wrote:
> On Mon, Apr 08, 2013 at 10:27:23PM +0100, Stephen Boyd wrote:
>> On an SMP system with only one global clockevent and a dummy
>> clockevent per CPU we run into problems. We want the dummy
>> clockevents to be registered as the per CPU tick devices, but
>> we can only achieve that if we register the dummy clockevents
>> before the global clockevent or if we artificially inflate the
>> rating of the dummy clockevents to be higher than the rating
>> of the global clockevent. Failure to do so leads to boot
>> hangs when the dummy timers are registered on all other CPUs
>> besides the CPU that accepted the global clockevent as its tick
>> device and there is no broadcast timer to poke the dummy
>> devices.
>>
>> If we're registering multiple clockevents and one clockevent is
>> global and the other is local to a particular CPU we should
>> choose to use the local clockevent regardless of the rating of
>> the device. This way, if the clockevent is a dummy it will take
>> the tick device duty as long as there isn't a higher rated tick
>> device and any global clockevent will be bumped out into
>> broadcast mode, fixing the problem described above.
> It might be worth pointing out that if dummy timers are only registered
> when there's more than one CPU, UP behaviour won't degrade from the
> current state of affairs.

Sure, I'll try to come up with something if I have to repost (looks like
I might have to rework the mct change).

>
>> Reported-by: Mark Rutland <[email protected]>
>> Cc: John Stultz <[email protected]>
>> Cc: Thomas Gleixner <[email protected]>
>> Signed-off-by: Stephen Boyd <[email protected]>
>> ---
>> kernel/time/tick-common.c | 5 +++--
>> 1 file changed, 3 insertions(+), 2 deletions(-)
>>
>> diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
>> index b1600a6..9ea59b9 100644
>> --- a/kernel/time/tick-common.c
>> +++ b/kernel/time/tick-common.c
>> @@ -251,9 +251,10 @@ static int tick_check_new_device(struct clock_event_device *newdev)
>> !(newdev->features & CLOCK_EVT_FEAT_ONESHOT))
>> goto out_bc;
>> /*
>> - * Check the rating
>> + * Check the rating, but prefer CPU local devices
>> */
>> - if (curdev->rating >= newdev->rating)
>> + if (curdev->rating >= newdev->rating &&
>> + cpumask_equal(curdev->cpumask, newdev->cpumask))
>> goto out_bc;
>> }
> This looks good to me. I tested this on a TC2 with a v3.9-rc6 kernel
> without architected timer support. The patch restores the ability to use
> the sp804 as a broadcast source.
>
> Tested-by: Mark Rutland <[email protected]>
>
> If possible I think this should sit in -next for a bit to make sure it
> doesn't have any unexpected side effects.

Thanks for testing.

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

2013-04-17 20:44:29

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCHv4 00/11] Remove ARM local timer API

Thomas,

Would you be able to pick up patches 1 and 2 from this series and
publish it as a stable branch? Preferably based on rc5 but I can always
merge it to rc5 and apply the rest of the patches.

Arnd/Olof,

Would you be able to merge in the rest of the patches to arm-soc? I can
provide a branch on 3.9-rc5 and a merge resolution with for-next in
arm-soc that you can pull to look at.

If not I will have to resend the series.

Thanks,
Stephen

On 04/08/13 14:27, Stephen Boyd wrote:
> 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 v3.9-rc5. I'm still looking for Acks/Tested-by
> on EXYNOS and PRIMA2.
>
> [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.
>
> Changes since v3:
> * New patch to fix SMP with dummy timers registered after a global timer
> * Push this_cpu_ptr lower to avoid preemptible false positive warnings
> * Collected acks/tested-bys
>
> Changes since v2:
> * Bug fixes in smp_twd from Tony Lindgren's testing
> * Move smp_twd to use late_time_init hook
> * Collected Acks
>
> Changes since v1:
> * Picked up Mark's generic dummy timer driver
> * Split out omap changes into new patch
>
> Mark Rutland (1):
> clocksource: add generic dummy timer driver
>
> Stephen Boyd (10):
> clockevents: Prefer CPU local devices over global devices
> ARM: smp: Remove duplicate dummy timer implementation
> ARM: smp_twd: Divorce smp_twd from local timer API
> ARM: OMAP2+: Divorce 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 | 87 ---------------------
> arch/arm/kernel/smp_twd.c | 64 +++++++++++-----
> arch/arm/mach-exynos/mct.c | 60 ++++++++++-----
> arch/arm/mach-msm/timer.c | 127 +++++++++++++++++--------------
> arch/arm/mach-omap2/Kconfig | 1 -
> arch/arm/mach-omap2/timer.c | 7 --
> arch/arm/mach-prima2/timer-marco.c | 100 +++++++++++++-----------
> drivers/clocksource/Makefile | 1 +
> drivers/clocksource/dummy_timer.c | 69 +++++++++++++++++
> drivers/clocksource/time-armada-370-xp.c | 92 +++++++++++-----------
> include/linux/time-armada-370-xp.h | 4 +-
> kernel/time/tick-common.c | 5 +-
> 14 files changed, 327 insertions(+), 336 deletions(-)
> delete mode 100644 arch/arm/include/asm/localtimer.h
> create mode 100644 drivers/clocksource/dummy_timer.c
>


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

2013-04-18 16:39:12

by Olof Johansson

[permalink] [raw]
Subject: Re: [PATCHv4 00/11] Remove ARM local timer API

On Wed, Apr 17, 2013 at 01:44:26PM -0700, Stephen Boyd wrote:
> Thomas,
>
> Would you be able to pick up patches 1 and 2 from this series and
> publish it as a stable branch? Preferably based on rc5 but I can always
> merge it to rc5 and apply the rest of the patches.
>
> Arnd/Olof,
>
> Would you be able to merge in the rest of the patches to arm-soc? I can
> provide a branch on 3.9-rc5 and a merge resolution with for-next in
> arm-soc that you can pull to look at.
>
> If not I will have to resend the series.

Hi,

I think this is 3.11 material at this point, so please send a fresh pull
request (or re-ask us to apply it) after -rc1.


-Olof