diff options
| -rw-r--r-- | arch/arm/Kconfig | 5 | ||||
| -rw-r--r-- | arch/arm/kernel/smp.c | 10 | ||||
| -rw-r--r-- | arch/arm/mach-realview/Makefile | 3 | ||||
| -rw-r--r-- | arch/arm/mach-realview/core.c | 10 | ||||
| -rw-r--r-- | arch/arm/mach-realview/localtimer.c | 39 | ||||
| -rw-r--r-- | arch/arm/mach-realview/platsmp.c | 6 | ||||
| -rw-r--r-- | include/asm-arm/smp.h | 13 |
7 files changed, 69 insertions, 17 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index b82828e768ad..a0aeecc33c73 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
| @@ -33,6 +33,11 @@ config GENERIC_CLOCKEVENTS | |||
| 33 | bool | 33 | bool |
| 34 | default n | 34 | default n |
| 35 | 35 | ||
| 36 | config GENERIC_CLOCKEVENTS_BROADCAST | ||
| 37 | bool | ||
| 38 | depends on GENERIC_CLOCKEVENTS | ||
| 39 | default y if SMP && !LOCAL_TIMERS | ||
| 40 | |||
| 36 | config MMU | 41 | config MMU |
| 37 | bool | 42 | bool |
| 38 | default y | 43 | default y |
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index aef6f9ab900e..e9dfbab46cb6 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c | |||
| @@ -290,6 +290,11 @@ asmlinkage void __cpuinit secondary_start_kernel(void) | |||
| 290 | local_irq_enable(); | 290 | local_irq_enable(); |
| 291 | local_fiq_enable(); | 291 | local_fiq_enable(); |
| 292 | 292 | ||
| 293 | /* | ||
| 294 | * Setup local timer for this CPU. | ||
| 295 | */ | ||
| 296 | local_timer_setup(cpu); | ||
| 297 | |||
| 293 | calibrate_delay(); | 298 | calibrate_delay(); |
| 294 | 299 | ||
| 295 | smp_store_cpu_info(cpu); | 300 | smp_store_cpu_info(cpu); |
| @@ -300,11 +305,6 @@ asmlinkage void __cpuinit secondary_start_kernel(void) | |||
| 300 | cpu_set(cpu, cpu_online_map); | 305 | cpu_set(cpu, cpu_online_map); |
| 301 | 306 | ||
| 302 | /* | 307 | /* |
| 303 | * Setup local timer for this CPU. | ||
| 304 | */ | ||
| 305 | local_timer_setup(cpu); | ||
| 306 | |||
| 307 | /* | ||
| 308 | * OK, it's off to the idle thread for us | 308 | * OK, it's off to the idle thread for us |
| 309 | */ | 309 | */ |
| 310 | cpu_idle(); | 310 | cpu_idle(); |
diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile index 36e76ba937fc..ca1e390c3c28 100644 --- a/arch/arm/mach-realview/Makefile +++ b/arch/arm/mach-realview/Makefile | |||
| @@ -4,6 +4,5 @@ | |||
| 4 | 4 | ||
| 5 | obj-y := core.o clock.o | 5 | obj-y := core.o clock.o |
| 6 | obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o | 6 | obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o |
| 7 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o | 7 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o localtimer.o |
| 8 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o | 8 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o |
| 9 | obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o | ||
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index 6c68deed84dc..8cabfec31da2 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c | |||
| @@ -596,12 +596,20 @@ static void __init realview_clocksource_init(void) | |||
| 596 | } | 596 | } |
| 597 | 597 | ||
| 598 | /* | 598 | /* |
| 599 | * Set up timer interrupt, and return the current time in seconds. | 599 | * Set up the clock source and clock events devices |
| 600 | */ | 600 | */ |
| 601 | static void __init realview_timer_init(void) | 601 | static void __init realview_timer_init(void) |
| 602 | { | 602 | { |
| 603 | u32 val; | 603 | u32 val; |
| 604 | 604 | ||
| 605 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST | ||
| 606 | /* | ||
| 607 | * The dummy clock device has to be registered before the main device | ||
| 608 | * so that the latter will broadcast the clock events | ||
| 609 | */ | ||
| 610 | local_timer_setup(smp_processor_id()); | ||
| 611 | #endif | ||
| 612 | |||
| 605 | /* | 613 | /* |
| 606 | * set clock frequency: | 614 | * set clock frequency: |
| 607 | * REALVIEW_REFCLK is 32KHz | 615 | * REALVIEW_REFCLK is 32KHz |
diff --git a/arch/arm/mach-realview/localtimer.c b/arch/arm/mach-realview/localtimer.c index c7bdf04ab094..529eb6979e61 100644 --- a/arch/arm/mach-realview/localtimer.c +++ b/arch/arm/mach-realview/localtimer.c | |||
| @@ -14,6 +14,8 @@ | |||
| 14 | #include <linux/device.h> | 14 | #include <linux/device.h> |
| 15 | #include <linux/smp.h> | 15 | #include <linux/smp.h> |
| 16 | #include <linux/jiffies.h> | 16 | #include <linux/jiffies.h> |
| 17 | #include <linux/percpu.h> | ||
| 18 | #include <linux/clockchips.h> | ||
| 17 | 19 | ||
| 18 | #include <asm/mach/time.h> | 20 | #include <asm/mach/time.h> |
| 19 | #include <asm/hardware/arm_twd.h> | 21 | #include <asm/hardware/arm_twd.h> |
| @@ -25,6 +27,20 @@ | |||
| 25 | #define TWD_BASE(cpu) (__io_address(REALVIEW_TWD_BASE) + \ | 27 | #define TWD_BASE(cpu) (__io_address(REALVIEW_TWD_BASE) + \ |
| 26 | ((cpu) * REALVIEW_TWD_SIZE)) | 28 | ((cpu) * REALVIEW_TWD_SIZE)) |
| 27 | 29 | ||
| 30 | static DEFINE_PER_CPU(struct clock_event_device, local_clockevent); | ||
| 31 | |||
| 32 | /* | ||
| 33 | * Used on SMP for either the local timer or IPI_TIMER | ||
| 34 | */ | ||
| 35 | void local_timer_interrupt(void) | ||
| 36 | { | ||
| 37 | struct clock_event_device *clk = &__get_cpu_var(local_clockevent); | ||
| 38 | |||
| 39 | clk->event_handler(clk); | ||
| 40 | } | ||
| 41 | |||
| 42 | #ifdef CONFIG_LOCAL_TIMERS | ||
| 43 | |||
| 28 | static unsigned long mpcore_timer_rate; | 44 | static unsigned long mpcore_timer_rate; |
| 29 | 45 | ||
| 30 | /* | 46 | /* |
| @@ -127,3 +143,26 @@ void __cpuexit local_timer_stop(unsigned int cpu) | |||
| 127 | { | 143 | { |
| 128 | __raw_writel(0, TWD_BASE(cpu) + TWD_TIMER_CONTROL); | 144 | __raw_writel(0, TWD_BASE(cpu) + TWD_TIMER_CONTROL); |
| 129 | } | 145 | } |
| 146 | |||
| 147 | #else /* CONFIG_LOCAL_TIMERS */ | ||
| 148 | |||
| 149 | static void dummy_timer_set_mode(enum clock_event_mode mode, | ||
| 150 | struct clock_event_device *clk) | ||
| 151 | { | ||
| 152 | } | ||
| 153 | |||
| 154 | void __cpuinit local_timer_setup(unsigned int cpu) | ||
| 155 | { | ||
| 156 | struct clock_event_device *clk = &per_cpu(local_clockevent, cpu); | ||
| 157 | |||
| 158 | clk->name = "dummy_timer"; | ||
| 159 | clk->features = CLOCK_EVT_FEAT_DUMMY; | ||
| 160 | clk->rating = 200; | ||
| 161 | clk->set_mode = dummy_timer_set_mode; | ||
| 162 | clk->broadcast = smp_timer_broadcast; | ||
| 163 | clk->cpumask = cpumask_of_cpu(cpu); | ||
| 164 | |||
| 165 | clockevents_register_device(clk); | ||
| 166 | } | ||
| 167 | |||
| 168 | #endif /* !CONFIG_LOCAL_TIMERS */ | ||
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index fce3596f9950..bb5eaa48520d 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c | |||
| @@ -187,10 +187,14 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
| 187 | if (max_cpus > ncores) | 187 | if (max_cpus > ncores) |
| 188 | max_cpus = ncores; | 188 | max_cpus = ncores; |
| 189 | 189 | ||
| 190 | #ifdef CONFIG_LOCAL_TIMERS | ||
| 190 | /* | 191 | /* |
| 191 | * Enable the local timer for primary CPU | 192 | * Enable the local timer for primary CPU. If the device is |
| 193 | * dummy (!CONFIG_LOCAL_TIMERS), it was already registers in | ||
| 194 | * realview_timer_init | ||
| 192 | */ | 195 | */ |
| 193 | local_timer_setup(cpu); | 196 | local_timer_setup(cpu); |
| 197 | #endif | ||
| 194 | 198 | ||
| 195 | /* | 199 | /* |
| 196 | * Initialise the present map, which describes the set of CPUs | 200 | * Initialise the present map, which describes the set of CPUs |
diff --git a/include/asm-arm/smp.h b/include/asm-arm/smp.h index 1f7c51a1886d..af99636db400 100644 --- a/include/asm-arm/smp.h +++ b/include/asm-arm/smp.h | |||
| @@ -107,10 +107,6 @@ extern void platform_cpu_enable(unsigned int cpu); | |||
| 107 | extern void local_timer_interrupt(void); | 107 | extern void local_timer_interrupt(void); |
| 108 | 108 | ||
| 109 | #ifdef CONFIG_LOCAL_TIMERS | 109 | #ifdef CONFIG_LOCAL_TIMERS |
| 110 | /* | ||
| 111 | * Setup a local timer interrupt for a CPU. | ||
| 112 | */ | ||
| 113 | extern void local_timer_setup(unsigned int cpu); | ||
| 114 | 110 | ||
| 115 | /* | 111 | /* |
| 116 | * Stop a local timer interrupt. | 112 | * Stop a local timer interrupt. |
| @@ -124,10 +120,6 @@ extern int local_timer_ack(void); | |||
| 124 | 120 | ||
| 125 | #else | 121 | #else |
| 126 | 122 | ||
| 127 | static inline void local_timer_setup(unsigned int cpu) | ||
| 128 | { | ||
| 129 | } | ||
| 130 | |||
| 131 | static inline void local_timer_stop(unsigned int cpu) | 123 | static inline void local_timer_stop(unsigned int cpu) |
| 132 | { | 124 | { |
| 133 | } | 125 | } |
| @@ -135,6 +127,11 @@ static inline void local_timer_stop(unsigned int cpu) | |||
| 135 | #endif | 127 | #endif |
| 136 | 128 | ||
| 137 | /* | 129 | /* |
| 130 | * Setup a local timer interrupt for a CPU. | ||
| 131 | */ | ||
| 132 | extern void local_timer_setup(unsigned int cpu); | ||
| 133 | |||
| 134 | /* | ||
| 138 | * show local interrupt info | 135 | * show local interrupt info |
| 139 | */ | 136 | */ |
| 140 | extern void show_local_irqs(struct seq_file *); | 137 | extern void show_local_irqs(struct seq_file *); |
