[ARM] 4814/1: RealView: Add broadcasting clockevents support for ARM11MPCore
This patch adds dummy local timers for each CPU so that the board clock device is used to broadcast events to the other CPUs. The patch also adds the declaration for the dummy_timer_setup function (the equivalent of local_timer_setup when CONFIG_LOCAL_TIMERS is not set). Due to the way clockevents work, the dummy timer on the first CPU has to be registered before the board timer. Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
3e45999096
commit
a8655e83fc
|
@ -33,6 +33,11 @@ config GENERIC_CLOCKEVENTS
|
||||||
bool
|
bool
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
config GENERIC_CLOCKEVENTS_BROADCAST
|
||||||
|
bool
|
||||||
|
depends on GENERIC_CLOCKEVENTS
|
||||||
|
default y if SMP && !LOCAL_TIMERS
|
||||||
|
|
||||||
config MMU
|
config MMU
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|
|
@ -290,6 +290,11 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
|
||||||
local_irq_enable();
|
local_irq_enable();
|
||||||
local_fiq_enable();
|
local_fiq_enable();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup local timer for this CPU.
|
||||||
|
*/
|
||||||
|
local_timer_setup(cpu);
|
||||||
|
|
||||||
calibrate_delay();
|
calibrate_delay();
|
||||||
|
|
||||||
smp_store_cpu_info(cpu);
|
smp_store_cpu_info(cpu);
|
||||||
|
@ -299,11 +304,6 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
|
||||||
*/
|
*/
|
||||||
cpu_set(cpu, cpu_online_map);
|
cpu_set(cpu, cpu_online_map);
|
||||||
|
|
||||||
/*
|
|
||||||
* Setup local timer for this CPU.
|
|
||||||
*/
|
|
||||||
local_timer_setup(cpu);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OK, it's off to the idle thread for us
|
* OK, it's off to the idle thread for us
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,6 +4,5 @@
|
||||||
|
|
||||||
obj-y := core.o clock.o
|
obj-y := core.o clock.o
|
||||||
obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o
|
obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o
|
||||||
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
|
obj-$(CONFIG_SMP) += platsmp.o headsmp.o localtimer.o
|
||||||
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
||||||
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
|
|
||||||
|
|
|
@ -596,12 +596,20 @@ static void __init realview_clocksource_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up timer interrupt, and return the current time in seconds.
|
* Set up the clock source and clock events devices
|
||||||
*/
|
*/
|
||||||
static void __init realview_timer_init(void)
|
static void __init realview_timer_init(void)
|
||||||
{
|
{
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
|
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
|
||||||
|
/*
|
||||||
|
* The dummy clock device has to be registered before the main device
|
||||||
|
* so that the latter will broadcast the clock events
|
||||||
|
*/
|
||||||
|
local_timer_setup(smp_processor_id());
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set clock frequency:
|
* set clock frequency:
|
||||||
* REALVIEW_REFCLK is 32KHz
|
* REALVIEW_REFCLK is 32KHz
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/smp.h>
|
#include <linux/smp.h>
|
||||||
#include <linux/jiffies.h>
|
#include <linux/jiffies.h>
|
||||||
|
#include <linux/percpu.h>
|
||||||
|
#include <linux/clockchips.h>
|
||||||
|
|
||||||
#include <asm/mach/time.h>
|
#include <asm/mach/time.h>
|
||||||
#include <asm/hardware/arm_twd.h>
|
#include <asm/hardware/arm_twd.h>
|
||||||
|
@ -25,6 +27,20 @@
|
||||||
#define TWD_BASE(cpu) (__io_address(REALVIEW_TWD_BASE) + \
|
#define TWD_BASE(cpu) (__io_address(REALVIEW_TWD_BASE) + \
|
||||||
((cpu) * REALVIEW_TWD_SIZE))
|
((cpu) * REALVIEW_TWD_SIZE))
|
||||||
|
|
||||||
|
static DEFINE_PER_CPU(struct clock_event_device, local_clockevent);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used on SMP for either the local timer or IPI_TIMER
|
||||||
|
*/
|
||||||
|
void local_timer_interrupt(void)
|
||||||
|
{
|
||||||
|
struct clock_event_device *clk = &__get_cpu_var(local_clockevent);
|
||||||
|
|
||||||
|
clk->event_handler(clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_LOCAL_TIMERS
|
||||||
|
|
||||||
static unsigned long mpcore_timer_rate;
|
static unsigned long mpcore_timer_rate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -127,3 +143,26 @@ void __cpuexit local_timer_stop(unsigned int cpu)
|
||||||
{
|
{
|
||||||
__raw_writel(0, TWD_BASE(cpu) + TWD_TIMER_CONTROL);
|
__raw_writel(0, TWD_BASE(cpu) + TWD_TIMER_CONTROL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else /* CONFIG_LOCAL_TIMERS */
|
||||||
|
|
||||||
|
static void dummy_timer_set_mode(enum clock_event_mode mode,
|
||||||
|
struct clock_event_device *clk)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void __cpuinit local_timer_setup(unsigned int cpu)
|
||||||
|
{
|
||||||
|
struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
|
||||||
|
|
||||||
|
clk->name = "dummy_timer";
|
||||||
|
clk->features = CLOCK_EVT_FEAT_DUMMY;
|
||||||
|
clk->rating = 200;
|
||||||
|
clk->set_mode = dummy_timer_set_mode;
|
||||||
|
clk->broadcast = smp_timer_broadcast;
|
||||||
|
clk->cpumask = cpumask_of_cpu(cpu);
|
||||||
|
|
||||||
|
clockevents_register_device(clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !CONFIG_LOCAL_TIMERS */
|
||||||
|
|
|
@ -187,10 +187,14 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
|
||||||
if (max_cpus > ncores)
|
if (max_cpus > ncores)
|
||||||
max_cpus = ncores;
|
max_cpus = ncores;
|
||||||
|
|
||||||
|
#ifdef CONFIG_LOCAL_TIMERS
|
||||||
/*
|
/*
|
||||||
* Enable the local timer for primary CPU
|
* Enable the local timer for primary CPU. If the device is
|
||||||
|
* dummy (!CONFIG_LOCAL_TIMERS), it was already registers in
|
||||||
|
* realview_timer_init
|
||||||
*/
|
*/
|
||||||
local_timer_setup(cpu);
|
local_timer_setup(cpu);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialise the present map, which describes the set of CPUs
|
* Initialise the present map, which describes the set of CPUs
|
||||||
|
|
|
@ -107,10 +107,6 @@ extern void platform_cpu_enable(unsigned int cpu);
|
||||||
extern void local_timer_interrupt(void);
|
extern void local_timer_interrupt(void);
|
||||||
|
|
||||||
#ifdef CONFIG_LOCAL_TIMERS
|
#ifdef CONFIG_LOCAL_TIMERS
|
||||||
/*
|
|
||||||
* Setup a local timer interrupt for a CPU.
|
|
||||||
*/
|
|
||||||
extern void local_timer_setup(unsigned int cpu);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stop a local timer interrupt.
|
* Stop a local timer interrupt.
|
||||||
|
@ -124,16 +120,17 @@ extern int local_timer_ack(void);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static inline void local_timer_setup(unsigned int cpu)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void local_timer_stop(unsigned int cpu)
|
static inline void local_timer_stop(unsigned int cpu)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup a local timer interrupt for a CPU.
|
||||||
|
*/
|
||||||
|
extern void local_timer_setup(unsigned int cpu);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* show local interrupt info
|
* show local interrupt info
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue