Commit bc28248e authored by Russell King's avatar Russell King Committed by Russell King

[ARM] smp: move core localtimer support out of platform specific files

Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent ee348d5a
...@@ -859,6 +859,7 @@ source "kernel/time/Kconfig" ...@@ -859,6 +859,7 @@ source "kernel/time/Kconfig"
config SMP config SMP
bool "Symmetric Multi-Processing (EXPERIMENTAL)" bool "Symmetric Multi-Processing (EXPERIMENTAL)"
depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP) depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP)
depends on GENERIC_CLOCKEVENTS
select USE_GENERIC_SMP_HELPERS select USE_GENERIC_SMP_HELPERS
help help
This enables support for systems with more than one CPU. If you have This enables support for systems with more than one CPU. If you have
......
/*
* 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
struct clock_event_device;
/*
* Setup a per-cpu timer, whether it be a local timer or dummy broadcast
*/
void percpu_timer_setup(void);
/*
* Called from assembly, this is the local timer IRQ handler
*/
asmlinkage void do_local_timer(struct pt_regs *);
#ifdef CONFIG_LOCAL_TIMERS
/*
* Platform provides this to acknowledge a local timer IRQ.
* Returns true if the local timer IRQ is to be processed.
*/
int local_timer_ack(void);
/*
* Stop a local timer interrupt.
*/
void local_timer_stop(void);
/*
* Setup a local timer interrupt for a CPU.
*/
void local_timer_setup(struct clock_event_device *);
#else
static inline void local_timer_stop(void)
{
}
#endif
#endif
...@@ -55,11 +55,6 @@ extern void smp_store_cpu_info(unsigned int cpuid); ...@@ -55,11 +55,6 @@ extern void smp_store_cpu_info(unsigned int cpuid);
*/ */
extern void smp_cross_call(const struct cpumask *mask); extern void smp_cross_call(const struct cpumask *mask);
/*
* Broadcast a clock event to other CPUs.
*/
extern void smp_timer_broadcast(const struct cpumask *mask);
/* /*
* Boot a secondary CPU, and assign it the specified idle task. * Boot a secondary CPU, and assign it the specified idle task.
* This also gives us the initial stack to use for this CPU. * This also gives us the initial stack to use for this CPU.
...@@ -100,44 +95,9 @@ extern void arch_send_call_function_single_ipi(int cpu); ...@@ -100,44 +95,9 @@ extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask #define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask
/*
* Local timer interrupt handling function (can be IPI'ed).
*/
extern void local_timer_interrupt(void);
#ifdef CONFIG_LOCAL_TIMERS
/*
* Stop a local timer interrupt.
*/
extern void local_timer_stop(void);
/*
* Platform provides this to acknowledge a local timer IRQ
*/
extern int local_timer_ack(void);
#else
static inline void local_timer_stop(void)
{
}
#endif
/*
* Setup a local timer interrupt for a CPU.
*/
extern void local_timer_setup(void);
/* /*
* show local interrupt info * show local interrupt info
*/ */
extern void show_local_irqs(struct seq_file *); extern void show_local_irqs(struct seq_file *);
/*
* Called from assembly, this is the local timer IRQ handler
*/
asmlinkage void do_local_timer(struct pt_regs *);
#endif /* ifndef __ASM_ARM_SMP_H */ #endif /* ifndef __ASM_ARM_SMP_H */
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/percpu.h>
#include <linux/clockchips.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
...@@ -32,6 +34,7 @@ ...@@ -32,6 +34,7 @@
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/localtimer.h>
/* /*
* as from 2.5, kernels no longer have an init_tasks structure * as from 2.5, kernels no longer have an init_tasks structure
...@@ -274,9 +277,9 @@ asmlinkage void __cpuinit secondary_start_kernel(void) ...@@ -274,9 +277,9 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
local_fiq_enable(); local_fiq_enable();
/* /*
* Setup local timer for this CPU. * Setup the percpu timer for this CPU.
*/ */
local_timer_setup(); percpu_timer_setup();
calibrate_delay(); calibrate_delay();
...@@ -383,10 +386,16 @@ void show_local_irqs(struct seq_file *p) ...@@ -383,10 +386,16 @@ void show_local_irqs(struct seq_file *p)
seq_putc(p, '\n'); seq_putc(p, '\n');
} }
/*
* Timer (local or broadcast) support
*/
static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent);
static void ipi_timer(void) static void ipi_timer(void)
{ {
struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent);
irq_enter(); irq_enter();
local_timer_interrupt(); evt->event_handler(evt);
irq_exit(); irq_exit();
} }
...@@ -405,6 +414,42 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs) ...@@ -405,6 +414,42 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs)
} }
#endif #endif
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
static void smp_timer_broadcast(const struct cpumask *mask)
{
send_ipi_message(mask, IPI_TIMER);
}
static void broadcast_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
}
static void local_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 = 400;
evt->mult = 1;
evt->set_mode = broadcast_timer_set_mode;
evt->broadcast = smp_timer_broadcast;
clockevents_register_device(evt);
}
#endif
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);
local_timer_setup(evt);
}
static DEFINE_SPINLOCK(stop_lock); static DEFINE_SPINLOCK(stop_lock);
/* /*
...@@ -501,11 +546,6 @@ void smp_send_reschedule(int cpu) ...@@ -501,11 +546,6 @@ void smp_send_reschedule(int cpu)
send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
} }
void smp_timer_broadcast(const struct cpumask *mask)
{
send_ipi_message(mask, IPI_TIMER);
}
void smp_send_stop(void) void smp_send_stop(void)
{ {
cpumask_t mask = cpu_online_map; cpumask_t mask = cpu_online_map;
......
...@@ -11,10 +11,8 @@ ...@@ -11,10 +11,8 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/delay.h> #include <linux/delay.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 <linux/clockchips.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -24,18 +22,6 @@ ...@@ -24,18 +22,6 @@
#include <mach/hardware.h> #include <mach/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
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 #ifdef CONFIG_LOCAL_TIMERS
/* set up by the platform code */ /* set up by the platform code */
...@@ -44,7 +30,7 @@ void __iomem *twd_base; ...@@ -44,7 +30,7 @@ void __iomem *twd_base;
static unsigned long mpcore_timer_rate; static unsigned long mpcore_timer_rate;
static void local_timer_set_mode(enum clock_event_mode mode, static void local_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *clk) struct clock_event_device *evt)
{ {
unsigned long ctrl; unsigned long ctrl;
...@@ -140,32 +126,29 @@ static void __cpuinit twd_calibrate_rate(void) ...@@ -140,32 +126,29 @@ static void __cpuinit twd_calibrate_rate(void)
/* /*
* Setup the local clock events for a CPU. * Setup the local clock events for a CPU.
*/ */
void __cpuinit local_timer_setup(void) void __cpuinit local_timer_setup(struct clock_event_device *evt)
{ {
unsigned int cpu = smp_processor_id();
struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
unsigned long flags; unsigned long flags;
twd_calibrate_rate(); twd_calibrate_rate();
clk->name = "local_timer"; evt->name = "local_timer";
clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
clk->rating = 350; evt->rating = 350;
clk->set_mode = local_timer_set_mode; evt->set_mode = local_timer_set_mode;
clk->set_next_event = local_timer_set_next_event; evt->set_next_event = local_timer_set_next_event;
clk->irq = IRQ_LOCALTIMER; evt->irq = IRQ_LOCALTIMER;
clk->cpumask = cpumask_of(cpu); evt->shift = 20;
clk->shift = 20; evt->mult = div_sc(mpcore_timer_rate, NSEC_PER_SEC, evt->shift);
clk->mult = div_sc(mpcore_timer_rate, NSEC_PER_SEC, clk->shift); evt->max_delta_ns = clockevent_delta2ns(0xffffffff, evt);
clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk); evt->min_delta_ns = clockevent_delta2ns(0xf, evt);
clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
/* Make sure our local interrupt controller has this enabled */ /* Make sure our local interrupt controller has this enabled */
local_irq_save(flags); local_irq_save(flags);
get_irq_chip(IRQ_LOCALTIMER)->unmask(IRQ_LOCALTIMER); get_irq_chip(IRQ_LOCALTIMER)->unmask(IRQ_LOCALTIMER);
local_irq_restore(flags); local_irq_restore(flags);
clockevents_register_device(clk); clockevents_register_device(evt);
} }
/* /*
...@@ -176,29 +159,4 @@ void __cpuexit local_timer_stop(void) ...@@ -176,29 +159,4 @@ void __cpuexit local_timer_stop(void)
__raw_writel(0, twd_base + TWD_TIMER_CONTROL); __raw_writel(0, twd_base + TWD_TIMER_CONTROL);
} }
#else /* CONFIG_LOCAL_TIMERS */ #endif /* CONFIG_LOCAL_TIMERS */
static void dummy_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *clk)
{
}
void __cpuinit local_timer_setup(void)
{
unsigned int cpu = smp_processor_id();
struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
clk->name = "dummy_timer";
clk->features = CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_DUMMY;
clk->rating = 400;
clk->mult = 1;
clk->set_mode = dummy_timer_set_mode;
clk->broadcast = smp_timer_broadcast;
clk->cpumask = cpumask_of(cpu);
clockevents_register_device(clk);
}
#endif /* !CONFIG_LOCAL_TIMERS */
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/localtimer.h>
#include <mach/board-eb.h> #include <mach/board-eb.h>
#include <mach/board-pb11mp.h> #include <mach/board-pb11mp.h>
...@@ -217,13 +218,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) ...@@ -217,13 +218,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
if (max_cpus > ncores) if (max_cpus > ncores)
max_cpus = ncores; max_cpus = ncores;
#if defined(CONFIG_LOCAL_TIMERS) || defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
/*
* Enable the local timer or broadcast device for the boot CPU.
*/
local_timer_setup();
#endif
/* /*
* Initialise the present map, which describes the set of CPUs * Initialise the present map, which describes the set of CPUs
* actually populated at the present time. * actually populated at the present time.
...@@ -239,6 +233,12 @@ void __init smp_prepare_cpus(unsigned int max_cpus) ...@@ -239,6 +233,12 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
* WFI * WFI
*/ */
if (max_cpus > 1) { if (max_cpus > 1) {
/*
* Enable the local timer or broadcast device for the
* boot CPU, but only if we have more than one CPU.
*/
percpu_timer_setup();
scu_enable(); scu_enable();
poke_milo(); poke_milo();
} }
......
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