aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/smp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/smp.c')
-rw-r--r--arch/arm/kernel/smp.c126
1 files changed, 123 insertions, 3 deletions
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index ebd8ad274d76..dea7a925c7e2 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -19,14 +19,15 @@
19#include <linux/mm.h> 19#include <linux/mm.h>
20#include <linux/err.h> 20#include <linux/err.h>
21#include <linux/cpu.h> 21#include <linux/cpu.h>
22#include <linux/smp.h>
23#include <linux/seq_file.h> 22#include <linux/seq_file.h>
24#include <linux/irq.h> 23#include <linux/irq.h>
25#include <linux/percpu.h> 24#include <linux/percpu.h>
26#include <linux/clockchips.h> 25#include <linux/clockchips.h>
27#include <linux/completion.h> 26#include <linux/completion.h>
27#include <linux/cpufreq.h>
28 28
29#include <linux/atomic.h> 29#include <linux/atomic.h>
30#include <asm/smp.h>
30#include <asm/cacheflush.h> 31#include <asm/cacheflush.h>
31#include <asm/cpu.h> 32#include <asm/cpu.h>
32#include <asm/cputype.h> 33#include <asm/cputype.h>
@@ -42,6 +43,7 @@
42#include <asm/ptrace.h> 43#include <asm/ptrace.h>
43#include <asm/localtimer.h> 44#include <asm/localtimer.h>
44#include <asm/smp_plat.h> 45#include <asm/smp_plat.h>
46#include <asm/mach/arch.h>
45 47
46/* 48/*
47 * as from 2.5, kernels no longer have an init_tasks structure 49 * as from 2.5, kernels no longer have an init_tasks structure
@@ -50,6 +52,12 @@
50 */ 52 */
51struct secondary_data secondary_data; 53struct secondary_data secondary_data;
52 54
55/*
56 * control for which core is the next to come out of the secondary
57 * boot "holding pen"
58 */
59volatile int __cpuinitdata pen_release = -1;
60
53enum ipi_msg_type { 61enum ipi_msg_type {
54 IPI_TIMER = 2, 62 IPI_TIMER = 2,
55 IPI_RESCHEDULE, 63 IPI_RESCHEDULE,
@@ -60,6 +68,14 @@ enum ipi_msg_type {
60 68
61static DECLARE_COMPLETION(cpu_running); 69static DECLARE_COMPLETION(cpu_running);
62 70
71static struct smp_operations smp_ops;
72
73void __init smp_set_ops(struct smp_operations *ops)
74{
75 if (ops)
76 smp_ops = *ops;
77};
78
63int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle) 79int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
64{ 80{
65 int ret; 81 int ret;
@@ -100,13 +116,64 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
100 return ret; 116 return ret;
101} 117}
102 118
119/* platform specific SMP operations */
120void __init smp_init_cpus(void)
121{
122 if (smp_ops.smp_init_cpus)
123 smp_ops.smp_init_cpus();
124}
125
126static void __init platform_smp_prepare_cpus(unsigned int max_cpus)
127{
128 if (smp_ops.smp_prepare_cpus)
129 smp_ops.smp_prepare_cpus(max_cpus);
130}
131
132static void __cpuinit platform_secondary_init(unsigned int cpu)
133{
134 if (smp_ops.smp_secondary_init)
135 smp_ops.smp_secondary_init(cpu);
136}
137
138int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
139{
140 if (smp_ops.smp_boot_secondary)
141 return smp_ops.smp_boot_secondary(cpu, idle);
142 return -ENOSYS;
143}
144
103#ifdef CONFIG_HOTPLUG_CPU 145#ifdef CONFIG_HOTPLUG_CPU
104static void percpu_timer_stop(void); 146static void percpu_timer_stop(void);
105 147
148static int platform_cpu_kill(unsigned int cpu)
149{
150 if (smp_ops.cpu_kill)
151 return smp_ops.cpu_kill(cpu);
152 return 1;
153}
154
155static void platform_cpu_die(unsigned int cpu)
156{
157 if (smp_ops.cpu_die)
158 smp_ops.cpu_die(cpu);
159}
160
161static int platform_cpu_disable(unsigned int cpu)
162{
163 if (smp_ops.cpu_disable)
164 return smp_ops.cpu_disable(cpu);
165
166 /*
167 * By default, allow disabling all CPUs except the first one,
168 * since this is special on a lot of platforms, e.g. because
169 * of clock tick interrupts.
170 */
171 return cpu == 0 ? -EPERM : 0;
172}
106/* 173/*
107 * __cpu_disable runs on the processor to be shutdown. 174 * __cpu_disable runs on the processor to be shutdown.
108 */ 175 */
109int __cpu_disable(void) 176int __cpuinit __cpu_disable(void)
110{ 177{
111 unsigned int cpu = smp_processor_id(); 178 unsigned int cpu = smp_processor_id();
112 int ret; 179 int ret;
@@ -149,7 +216,7 @@ static DECLARE_COMPLETION(cpu_died);
149 * called on the thread which is asking for a CPU to be shutdown - 216 * called on the thread which is asking for a CPU to be shutdown -
150 * waits until shutdown has completed, or it is timed out. 217 * waits until shutdown has completed, or it is timed out.
151 */ 218 */
152void __cpu_die(unsigned int cpu) 219void __cpuinit __cpu_die(unsigned int cpu)
153{ 220{
154 if (!wait_for_completion_timeout(&cpu_died, msecs_to_jiffies(5000))) { 221 if (!wait_for_completion_timeout(&cpu_died, msecs_to_jiffies(5000))) {
155 pr_err("CPU%u: cpu didn't die\n", cpu); 222 pr_err("CPU%u: cpu didn't die\n", cpu);
@@ -584,3 +651,56 @@ int setup_profiling_timer(unsigned int multiplier)
584{ 651{
585 return -EINVAL; 652 return -EINVAL;
586} 653}
654
655#ifdef CONFIG_CPU_FREQ
656
657static DEFINE_PER_CPU(unsigned long, l_p_j_ref);
658static DEFINE_PER_CPU(unsigned long, l_p_j_ref_freq);
659static unsigned long global_l_p_j_ref;
660static unsigned long global_l_p_j_ref_freq;
661
662static int cpufreq_callback(struct notifier_block *nb,
663 unsigned long val, void *data)
664{
665 struct cpufreq_freqs *freq = data;
666 int cpu = freq->cpu;
667
668 if (freq->flags & CPUFREQ_CONST_LOOPS)
669 return NOTIFY_OK;
670
671 if (!per_cpu(l_p_j_ref, cpu)) {
672 per_cpu(l_p_j_ref, cpu) =
673 per_cpu(cpu_data, cpu).loops_per_jiffy;
674 per_cpu(l_p_j_ref_freq, cpu) = freq->old;
675 if (!global_l_p_j_ref) {
676 global_l_p_j_ref = loops_per_jiffy;
677 global_l_p_j_ref_freq = freq->old;
678 }
679 }
680
681 if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
682 (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
683 (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
684 loops_per_jiffy = cpufreq_scale(global_l_p_j_ref,
685 global_l_p_j_ref_freq,
686 freq->new);
687 per_cpu(cpu_data, cpu).loops_per_jiffy =
688 cpufreq_scale(per_cpu(l_p_j_ref, cpu),
689 per_cpu(l_p_j_ref_freq, cpu),
690 freq->new);
691 }
692 return NOTIFY_OK;
693}
694
695static struct notifier_block cpufreq_notifier = {
696 .notifier_call = cpufreq_callback,
697};
698
699static int __init register_cpufreq_notifier(void)
700{
701 return cpufreq_register_notifier(&cpufreq_notifier,
702 CPUFREQ_TRANSITION_NOTIFIER);
703}
704core_initcall(register_cpufreq_notifier);
705
706#endif