summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Green <andy.green@linaro.org>2012-04-25 14:26:04 +0800
committerAndy Green <andy.green@linaro.org>2012-04-25 14:26:04 +0800
commit1456e06c1c55e607395a3048d0da28db6f8ae314 (patch)
treec7f1608fe1c9700285b8890ca090b055527b0aa5
parent7ad0c883cd8a3be6a9d468e8b2491d336a569088 (diff)
Signed-off-by: Andy Green <andy.green@linaro.org>
-rw-r--r--arch/arm/Kconfig7
-rw-r--r--arch/arm/include/asm/localtimer.h6
-rw-r--r--arch/arm/include/asm/smp_twd.h15
-rw-r--r--arch/arm/kernel/arch_timer.c5
-rw-r--r--arch/arm/kernel/smp.c36
-rw-r--r--arch/arm/kernel/smp_twd.c102
-rw-r--r--arch/arm/mach-omap2/Kconfig1
-rw-r--r--arch/arm/mach-omap2/timer.c45
8 files changed, 24 insertions, 193 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index d5042f9f3ad..a4422262328 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1583,10 +1583,6 @@ config HAVE_ARM_TWD
help
This options enables support for the ARM timer and watchdog unit
-config ARM_SMP_TWD
- bool
- select HAVE_ARM_TWD if SMP
-
choice
prompt "Memory split"
default VMSPLIT_3G
@@ -1625,8 +1621,9 @@ config HOTPLUG_CPU
config LOCAL_TIMERS
bool "Use local timer interrupts"
- depends on SMP #&& !ARM_SMP_TWD
+ 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/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h
index 6d69fd2b559..f77ffc1eb0c 100644
--- a/arch/arm/include/asm/localtimer.h
+++ b/arch/arm/include/asm/localtimer.h
@@ -20,12 +20,6 @@ struct local_timer_ops {
};
#ifdef CONFIG_LOCAL_TIMERS
-
-/*
- * Stop the local timer
- */
-void local_timer_stop(struct clock_event_device *);
-
/*
* Register a local timer driver
*/
diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h
index c9df3d2746d..0f01f4677bd 100644
--- a/arch/arm/include/asm/smp_twd.h
+++ b/arch/arm/include/asm/smp_twd.h
@@ -20,9 +20,6 @@
#include <linux/ioport.h>
-struct clock_event_device;
-struct resource;
-
struct twd_local_timer {
struct resource res[2];
};
@@ -44,17 +41,5 @@ static inline void twd_local_timer_of_register(void)
{
}
#endif
-//int __cpuinit twd_timer_setup(struct clock_event_device *);
-//void twd_timer_stop(struct clock_event_device *);
-struct resource;
-
-#ifdef CONFIG_HAVE_ARM_TWD
-int twd_timer_register(struct resource *res, int res_nr);
-#else
-static inline int twd_timer_register(struct resource *res, int res_nr)
-{
- return 0;
-}
-#endif
#endif
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index d27cfc3f8b9..a2df492a938 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -130,20 +130,17 @@ static int arch_timer_set_next_event(unsigned long evt,
static void __cpuinit arch_timer_setup(void *data)
{
- extern void smp_timer_broadcast(const struct cpumask *mask);
struct clock_event_device *clk = data;
/* Be safe... */
arch_timer_stop();
- clk->features = CLOCK_EVT_FEAT_ONESHOT |
- CLOCK_EVT_FEAT_C3STOP;
+ clk->features = CLOCK_EVT_FEAT_ONESHOT;
clk->name = "arch_sys_timer";
clk->rating = 450;
clk->set_mode = arch_timer_set_mode;
clk->set_next_event = arch_timer_set_next_event;
clk->irq = arch_timer_ppi;
clk->cpumask = cpumask_of(smp_processor_id());
- clk->broadcast = smp_timer_broadcast;
clockevents_config_and_register(clk, arch_timer_rate,
0xf, 0x7fffffff);
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index f401c3870fa..ac606c76a65 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -124,6 +124,7 @@ int __cpuinit __cpu_up(unsigned int cpu)
}
#ifdef CONFIG_HOTPLUG_CPU
+static void percpu_timer_stop(void);
/*
* __cpu_disable runs on the processor to be shutdown.
@@ -150,6 +151,11 @@ int __cpu_disable(void)
migrate_irqs();
/*
+ * Stop the local timer for this CPU.
+ */
+ percpu_timer_stop();
+
+ /*
* Flush user cache and TLB mappings, and then remove this CPU
* from the vm mask set of all processes.
*/
@@ -237,7 +243,6 @@ static void __cpuinit smp_store_cpu_info(unsigned int 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
@@ -288,10 +293,9 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
complete(&cpu_running);
/*
- * Setup the broadcast timer for this CPU.
+ * Setup the percpu timer for this CPU.
*/
- broadcast_timer_setup();
-
+ percpu_timer_setup();
local_irq_enable();
local_fiq_enable();
@@ -339,10 +343,10 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
max_cpus = ncores;
if (ncores > 1 && max_cpus) {
/*
- * Enable the broadcast device for the boot CPU, but
- * only if we have more than one CPU.
+ * Enable the local timer or broadcast device for the
+ * boot CPU, but only if we have more than one CPU.
*/
- broadcast_timer_setup();
+ percpu_timer_setup();
/*
* Initialise the present map, which describes the set of CPUs
@@ -414,7 +418,7 @@ u64 smp_irq_stat_cpu(unsigned int cpu)
}
/*
- * Broadcast timer support
+ * Timer (local or broadcast) support
*/
static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent);
@@ -425,7 +429,7 @@ static void ipi_timer(void)
}
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
-void smp_timer_broadcast(const struct cpumask *mask)
+static void smp_timer_broadcast(const struct cpumask *mask)
{
smp_cross_call(mask, IPI_TIMER);
}
@@ -433,17 +437,13 @@ void smp_timer_broadcast(const struct cpumask *mask)
#define smp_timer_broadcast NULL
#endif
-#if !(defined(CONFIG_ARM_SMP_TWD) || defined(CONFIG_ARM_ARCH_TIMER))
static void broadcast_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
}
-static void __cpuinit broadcast_timer_setup(void)
+static void __cpuinit broadcast_timer_setup(struct clock_event_device *evt)
{
- unsigned int cpu = smp_processor_id();
- struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
-
evt->name = "dummy_timer";
evt->features = CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_PERIODIC |
@@ -451,15 +451,9 @@ static void __cpuinit broadcast_timer_setup(void)
evt->rating = 400;
evt->mult = 1;
evt->set_mode = broadcast_timer_set_mode;
- evt->cpumask = cpumask_of(cpu);
- evt->broadcast = smp_timer_broadcast;
clockevents_register_device(evt);
}
-#else
-static void __cpuinit broadcast_timer_setup(void)
-{}
-#endif
static struct local_timer_ops *lt_ops;
@@ -483,7 +477,7 @@ static void __cpuinit percpu_timer_setup(void)
evt->broadcast = smp_timer_broadcast;
if (!lt_ops || lt_ops->setup(evt))
- broadcast_timer_setup();
+ broadcast_timer_setup(evt);
}
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 46a3ede5e09..53aa9a91d16 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -16,17 +16,16 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/smp.h>
-#include <linux/cpu.h>
#include <linux/jiffies.h>
#include <linux/clockchips.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
-#include <linux/interrupt.h>
#include <asm/smp_twd.h>
#include <asm/localtimer.h>
+#include <asm/hardware/gic.h>
/* set up by the platform code */
static void __iomem *twd_base;
@@ -34,8 +33,6 @@ static void __iomem *twd_base;
static struct clk *twd_clk;
static unsigned long twd_timer_rate;
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,
@@ -91,13 +88,12 @@ static int twd_timer_ack(void)
return 0;
}
-#if 1
+
static void twd_timer_stop(struct clock_event_device *clk)
{
twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
disable_percpu_irq(clk->irq);
}
-#endif
#ifdef CONFIG_CPU_FREQ
@@ -186,7 +182,7 @@ static void __cpuinit twd_calibrate_rate(void)
static irqreturn_t twd_handler(int irq, void *dev_id)
{
- struct clock_event_device *evt = dev_id;
+ struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
if (twd_timer_ack()) {
evt->event_handler(evt);
@@ -225,8 +221,6 @@ static struct clk *twd_get_clock(void)
return clk;
}
-extern void smp_timer_broadcast(const struct cpumask *mask);
-
/*
* Setup the local clock events for a CPU.
*/
@@ -247,15 +241,10 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
clk->name = "local_timer";
clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_C3STOP;
- clk->rating = 450; /* Make sure this is higher than broadcast */
+ clk->rating = 350;
clk->set_mode = twd_set_mode;
clk->set_next_event = twd_set_next_event;
clk->irq = twd_ppi;
- clk->shift = 20;
- clk->mult = div_sc(twd_timer_rate, NSEC_PER_SEC, clk->shift);
- clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
- clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
- clk->broadcast = smp_timer_broadcast;
this_cpu_clk = __this_cpu_ptr(twd_evt);
*this_cpu_clk = clk;
@@ -355,86 +344,3 @@ out:
WARN(err, "twd_local_timer_of_register failed (%d)\n", err);
}
#endif
-static struct clock_event_device __percpu *twd_clock_event;
-static int twd_ppi;
-
-static void __cpuinit twd_setup(void *data)
-{
- struct clock_event_device *clk = data;
- clk->cpumask = cpumask_of(smp_processor_id());
- clk->irq = twd_ppi;
- twd_timer_setup(clk);
-}
-
-static void __cpuinit twd_teardown(void *data)
-{
- struct clock_event_device *clk = data;
- twd_timer_stop(clk);
-}
-
-static int __cpuinit twd_cpu_notify(struct notifier_block *self,
- unsigned long action, void *data)
-{
- int cpu = (int)data;
- struct clock_event_device *clk = per_cpu_ptr(twd_clock_event, cpu);
-
- switch (action) {
- case CPU_STARTING:
- case CPU_STARTING_FROZEN:
- smp_call_function_single(cpu, twd_setup, clk, 1);
- break;
-
- case CPU_DOWN_PREPARE:
- case CPU_DOWN_PREPARE_FROZEN:
- smp_call_function_single(cpu, twd_teardown, clk, 1);
- break;
- }
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block __cpuinitdata twd_cpu_nb = {
- .notifier_call = twd_cpu_notify,
-};
-
-int __init twd_timer_register(struct resource *res, int res_nr)
-{
- struct clock_event_device *clk;
- int err;
-
- if (res_nr != 2 || res[1].start < 0)
- return -EINVAL;
-
- if (twd_base)
- return -EBUSY;
-
- twd_ppi = res[1].start;
- twd_base = ioremap(res[0].start, resource_size(&res[0]));
- twd_clock_event = alloc_percpu(struct clock_event_device);
- if (!twd_base || !twd_clock_event) {
- err = -ENOMEM;
- goto out_free;
- }
-
- err = request_percpu_irq(twd_ppi, twd_handler, "twd", twd_clock_event);
- if (err) {
- pr_err("twd: can't register interrupt %d (%d)\n",
- twd_ppi, err);
- goto out_free;
- }
-
- /* Immediately configure the timer on the boot CPU */
- clk = per_cpu_ptr(twd_clock_event, smp_processor_id());
- twd_setup(clk);
-
- register_cpu_notifier(&twd_cpu_nb);
-
- return 0;
-
-out_free:
- iounmap(twd_base);
- twd_base = NULL;
- free_percpu(twd_clock_event);
-
- return err;
-}
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 3ae992a1858..2b52699f585 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -47,7 +47,6 @@ config ARCH_OMAP4
select ARM_GIC
select HAVE_SMP
select LOCAL_TIMERS if SMP
- select ARM_SMP_TWD
select PL310_ERRATA_588369
select PL310_ERRATA_727915
select ARM_ERRATA_720789
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 49c449582ea..9df8bb155b4 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -339,45 +339,6 @@ OMAP_SYS_TIMER_INIT(3_secure, OMAP3_SECURE_TIMER, OMAP3_CLKEV_SOURCE,
OMAP_SYS_TIMER(3_secure)
#endif
-#ifdef CONFIG_ARM_SMP_TWD
-static struct resource omap4_twd_resources[] __initdata = {
- {
- .start = OMAP44XX_LOCAL_TWD_BASE,
- .end = OMAP44XX_LOCAL_TWD_BASE + 0x10,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = OMAP44XX_IRQ_LOCALTIMER,
- .end = OMAP44XX_IRQ_LOCALTIMER,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static void __init omap4_twd_init(void)
-{
- int err;
-
- /* Local timers are not supprted on OMAP4430 ES1.0 */
- if (omap_rev() == OMAP4430_REV_ES1_0)
- return;
-
- err = twd_timer_register(omap4_twd_resources,
- ARRAY_SIZE(omap4_twd_resources));
- if (err)
- pr_err("twd_timer_register failed %d\n", err);
-}
-
-#else
-#define omap4_twd_init NULL
-#endif
-
-/* main twd code wants to see this, despite it is deprecated now */
-
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
- return 0;
-}
-
#ifdef CONFIG_ARCH_OMAP4
#ifdef CONFIG_LOCAL_TIMERS
static DEFINE_TWD_LOCAL_TIMER(twd_local_timer,
@@ -389,7 +350,6 @@ static void __init omap4_timer_init(void)
{
omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE);
omap2_gp_clocksource_init(2, OMAP4_MPU_SOURCE);
-
#ifdef CONFIG_LOCAL_TIMERS
/* Local timers are not supprted on OMAP4430 ES1.0 */
if (omap_rev() != OMAP4430_REV_ES1_0) {
@@ -400,10 +360,9 @@ static void __init omap4_timer_init(void)
pr_err("twd_local_timer_register failed %d\n", err);
}
#endif
- late_time_init = omap4_twd_init;
}
OMAP_SYS_TIMER(4)
-#endif /* CONFIG_ARCH_OMAP4 */
+#endif
#ifdef CONFIG_ARM_ARCH_TIMER
static struct resource arch_timer_resources[] = {
@@ -442,7 +401,7 @@ static void __init omap5_timer_init(void)
late_time_init = arch_timer_init;
}
OMAP_SYS_TIMER(5)
-#endif /* CONFIG_ARCH_OMAP5 */
+#endif
/**
* omap2_dm_timer_set_src - change the timer input clock source