Commit 10034aab authored by Russell King's avatar Russell King

ARM: localtimer: clean up local timer on hot unplug

When a CPU is hot unplugged, the generic tick code cleans up the
clock event device, but fails to call down to the device's set_mode
function to actually shut the device down.

To work around this, we've historically had a local_timer_stop()
callback out of the hotplug code.  However, this adds needless
complexity when we have the clock event device itself available.

Explicitly call the clock event device's set_mode function with
CLOCK_EVT_MODE_UNUSED, so that the hardware can be cleanly shutdown
without any special external callbacks.  When/if the generic code
is fixed, percpu_timer_stop() can be killed off.
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent e3d9c625
...@@ -30,7 +30,6 @@ asmlinkage void do_local_timer(struct pt_regs *); ...@@ -30,7 +30,6 @@ asmlinkage void do_local_timer(struct pt_regs *);
#include "smp_twd.h" #include "smp_twd.h"
#define local_timer_ack() twd_timer_ack() #define local_timer_ack() twd_timer_ack()
#define local_timer_stop() twd_timer_stop()
#else #else
...@@ -40,11 +39,6 @@ asmlinkage void do_local_timer(struct pt_regs *); ...@@ -40,11 +39,6 @@ asmlinkage void do_local_timer(struct pt_regs *);
*/ */
int local_timer_ack(void); int local_timer_ack(void);
/*
* Stop a local timer interrupt.
*/
void local_timer_stop(void);
#endif #endif
/* /*
...@@ -52,12 +46,6 @@ void local_timer_stop(void); ...@@ -52,12 +46,6 @@ void local_timer_stop(void);
*/ */
void local_timer_setup(struct clock_event_device *); void local_timer_setup(struct clock_event_device *);
#else
static inline void local_timer_stop(void)
{
}
#endif #endif
#endif #endif
...@@ -22,7 +22,6 @@ struct clock_event_device; ...@@ -22,7 +22,6 @@ struct clock_event_device;
extern void __iomem *twd_base; extern void __iomem *twd_base;
void twd_timer_stop(void);
int twd_timer_ack(void); int twd_timer_ack(void);
void twd_timer_setup(struct clock_event_device *); void twd_timer_setup(struct clock_event_device *);
......
...@@ -189,6 +189,8 @@ int __cpuinit __cpu_up(unsigned int cpu) ...@@ -189,6 +189,8 @@ int __cpuinit __cpu_up(unsigned int cpu)
} }
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
static void percpu_timer_stop(void);
/* /*
* __cpu_disable runs on the processor to be shutdown. * __cpu_disable runs on the processor to be shutdown.
*/ */
...@@ -216,7 +218,7 @@ int __cpu_disable(void) ...@@ -216,7 +218,7 @@ int __cpu_disable(void)
/* /*
* Stop the local timer for this CPU. * Stop the local timer for this CPU.
*/ */
local_timer_stop(); percpu_timer_stop();
/* /*
* Flush user cache and TLB mappings, and then remove this CPU * Flush user cache and TLB mappings, and then remove this CPU
...@@ -539,6 +541,21 @@ void __cpuinit percpu_timer_setup(void) ...@@ -539,6 +541,21 @@ void __cpuinit percpu_timer_setup(void)
local_timer_setup(evt); local_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);
evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
}
#endif
static DEFINE_SPINLOCK(stop_lock); static DEFINE_SPINLOCK(stop_lock);
/* /*
......
...@@ -150,13 +150,3 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk) ...@@ -150,13 +150,3 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
clockevents_register_device(clk); clockevents_register_device(clk);
} }
#ifdef CONFIG_HOTPLUG_CPU
/*
* take a local timer down
*/
void twd_timer_stop(void)
{
__raw_writel(0, twd_base + TWD_TIMER_CONTROL);
}
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment