diff options
Diffstat (limited to 'arch/sh/kernel/smp.c')
-rw-r--r-- | arch/sh/kernel/smp.c | 167 |
1 files changed, 92 insertions, 75 deletions
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c index f93d5ffa9417..94075e1a1e61 100644 --- a/arch/sh/kernel/smp.c +++ b/arch/sh/kernel/smp.c | |||
@@ -3,68 +3,40 @@ | |||
3 | * | 3 | * |
4 | * SMP support for the SuperH processors. | 4 | * SMP support for the SuperH processors. |
5 | * | 5 | * |
6 | * Copyright (C) 2002, 2003 Paul Mundt | 6 | * Copyright (C) 2002 - 2007 Paul Mundt |
7 | * Copyright (C) 2006 - 2007 Akio Idehara | ||
7 | * | 8 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 9 | * This file is subject to the terms and conditions of the GNU General Public |
9 | * under the terms of the GNU General Public License as published by the | 10 | * License. See the file "COPYING" in the main directory of this archive |
10 | * Free Software Foundation; either version 2 of the License, or (at your | 11 | * for more details. |
11 | * option) any later version. | ||
12 | */ | 12 | */ |
13 | |||
14 | #include <linux/err.h> | 13 | #include <linux/err.h> |
15 | #include <linux/cache.h> | 14 | #include <linux/cache.h> |
16 | #include <linux/cpumask.h> | 15 | #include <linux/cpumask.h> |
17 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
18 | #include <linux/init.h> | 17 | #include <linux/init.h> |
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/spinlock.h> | 18 | #include <linux/spinlock.h> |
21 | #include <linux/threads.h> | 19 | #include <linux/mm.h> |
22 | #include <linux/module.h> | 20 | #include <linux/module.h> |
23 | #include <linux/time.h> | 21 | #include <linux/interrupt.h> |
24 | #include <linux/timex.h> | ||
25 | #include <linux/sched.h> | ||
26 | #include <linux/module.h> | ||
27 | |||
28 | #include <asm/atomic.h> | 22 | #include <asm/atomic.h> |
29 | #include <asm/processor.h> | 23 | #include <asm/processor.h> |
30 | #include <asm/system.h> | 24 | #include <asm/system.h> |
31 | #include <asm/mmu_context.h> | 25 | #include <asm/mmu_context.h> |
32 | #include <asm/smp.h> | 26 | #include <asm/smp.h> |
27 | #include <asm/cacheflush.h> | ||
28 | #include <asm/sections.h> | ||
33 | 29 | ||
34 | /* | 30 | int __cpu_number_map[NR_CPUS]; /* Map physical to logical */ |
35 | * This was written with the Sega Saturn (SMP SH-2 7604) in mind, | 31 | int __cpu_logical_map[NR_CPUS]; /* Map logical to physical */ |
36 | * but is designed to be usable regardless if there's an MMU | ||
37 | * present or not. | ||
38 | */ | ||
39 | struct sh_cpuinfo cpu_data[NR_CPUS]; | ||
40 | |||
41 | extern void per_cpu_trap_init(void); | ||
42 | 32 | ||
43 | cpumask_t cpu_possible_map; | 33 | cpumask_t cpu_possible_map; |
44 | EXPORT_SYMBOL(cpu_possible_map); | 34 | EXPORT_SYMBOL(cpu_possible_map); |
45 | 35 | ||
46 | cpumask_t cpu_online_map; | 36 | cpumask_t cpu_online_map; |
47 | EXPORT_SYMBOL(cpu_online_map); | 37 | EXPORT_SYMBOL(cpu_online_map); |
48 | static atomic_t cpus_booted = ATOMIC_INIT(0); | ||
49 | |||
50 | /* These are defined by the board-specific code. */ | ||
51 | 38 | ||
52 | /* | 39 | static atomic_t cpus_booted = ATOMIC_INIT(0); |
53 | * Cause the function described by call_data to be executed on the passed | ||
54 | * cpu. When the function has finished, increment the finished field of | ||
55 | * call_data. | ||
56 | */ | ||
57 | void __smp_send_ipi(unsigned int cpu, unsigned int action); | ||
58 | |||
59 | /* | ||
60 | * Find the number of available processors | ||
61 | */ | ||
62 | unsigned int __smp_probe_cpus(void); | ||
63 | |||
64 | /* | ||
65 | * Start a particular processor | ||
66 | */ | ||
67 | void __smp_slave_init(unsigned int cpu); | ||
68 | 40 | ||
69 | /* | 41 | /* |
70 | * Run specified function on a particular processor. | 42 | * Run specified function on a particular processor. |
@@ -73,74 +45,123 @@ void __smp_call_function(unsigned int cpu); | |||
73 | 45 | ||
74 | static inline void __init smp_store_cpu_info(unsigned int cpu) | 46 | static inline void __init smp_store_cpu_info(unsigned int cpu) |
75 | { | 47 | { |
76 | cpu_data[cpu].loops_per_jiffy = loops_per_jiffy; | 48 | struct sh_cpuinfo *c = cpu_data + cpu; |
49 | |||
50 | c->loops_per_jiffy = loops_per_jiffy; | ||
77 | } | 51 | } |
78 | 52 | ||
79 | void __init smp_prepare_cpus(unsigned int max_cpus) | 53 | void __init smp_prepare_cpus(unsigned int max_cpus) |
80 | { | 54 | { |
81 | unsigned int cpu = smp_processor_id(); | 55 | unsigned int cpu = smp_processor_id(); |
82 | int i; | ||
83 | 56 | ||
84 | atomic_set(&cpus_booted, 1); | 57 | init_new_context(current, &init_mm); |
85 | smp_store_cpu_info(cpu); | 58 | current_thread_info()->cpu = cpu; |
86 | 59 | plat_prepare_cpus(max_cpus); | |
87 | for (i = 0; i < __smp_probe_cpus(); i++) | 60 | |
88 | cpu_set(i, cpu_possible_map); | 61 | #ifndef CONFIG_HOTPLUG_CPU |
62 | cpu_present_map = cpu_possible_map; | ||
63 | #endif | ||
89 | } | 64 | } |
90 | 65 | ||
91 | void __devinit smp_prepare_boot_cpu(void) | 66 | void __devinit smp_prepare_boot_cpu(void) |
92 | { | 67 | { |
93 | unsigned int cpu = smp_processor_id(); | 68 | unsigned int cpu = smp_processor_id(); |
94 | 69 | ||
70 | __cpu_number_map[0] = cpu; | ||
71 | __cpu_logical_map[0] = cpu; | ||
72 | |||
95 | cpu_set(cpu, cpu_online_map); | 73 | cpu_set(cpu, cpu_online_map); |
96 | cpu_set(cpu, cpu_possible_map); | 74 | cpu_set(cpu, cpu_possible_map); |
97 | } | 75 | } |
98 | 76 | ||
99 | int __cpu_up(unsigned int cpu) | 77 | asmlinkage void __cpuinit start_secondary(void) |
100 | { | 78 | { |
101 | struct task_struct *tsk; | 79 | unsigned int cpu; |
80 | struct mm_struct *mm = &init_mm; | ||
102 | 81 | ||
103 | tsk = fork_idle(cpu); | 82 | atomic_inc(&mm->mm_count); |
83 | atomic_inc(&mm->mm_users); | ||
84 | current->active_mm = mm; | ||
85 | BUG_ON(current->mm); | ||
86 | enter_lazy_tlb(mm, current); | ||
87 | |||
88 | per_cpu_trap_init(); | ||
104 | 89 | ||
105 | if (IS_ERR(tsk)) | 90 | preempt_disable(); |
106 | panic("Failed forking idle task for cpu %d\n", cpu); | 91 | |
107 | 92 | local_irq_enable(); | |
108 | task_thread_info(tsk)->cpu = cpu; | 93 | |
94 | calibrate_delay(); | ||
95 | |||
96 | cpu = smp_processor_id(); | ||
97 | smp_store_cpu_info(cpu); | ||
109 | 98 | ||
110 | cpu_set(cpu, cpu_online_map); | 99 | cpu_set(cpu, cpu_online_map); |
111 | 100 | ||
112 | return 0; | 101 | cpu_idle(); |
113 | } | 102 | } |
114 | 103 | ||
115 | int start_secondary(void *unused) | 104 | extern struct { |
105 | unsigned long sp; | ||
106 | unsigned long bss_start; | ||
107 | unsigned long bss_end; | ||
108 | void *start_kernel_fn; | ||
109 | void *cpu_init_fn; | ||
110 | void *thread_info; | ||
111 | } stack_start; | ||
112 | |||
113 | int __cpuinit __cpu_up(unsigned int cpu) | ||
116 | { | 114 | { |
117 | unsigned int cpu; | 115 | struct task_struct *tsk; |
116 | unsigned long timeout; | ||
118 | 117 | ||
119 | cpu = smp_processor_id(); | 118 | tsk = fork_idle(cpu); |
119 | if (IS_ERR(tsk)) { | ||
120 | printk(KERN_ERR "Failed forking idle task for cpu %d\n", cpu); | ||
121 | return PTR_ERR(tsk); | ||
122 | } | ||
120 | 123 | ||
121 | atomic_inc(&init_mm.mm_count); | 124 | /* Fill in data in head.S for secondary cpus */ |
122 | current->active_mm = &init_mm; | 125 | stack_start.sp = tsk->thread.sp; |
126 | stack_start.thread_info = tsk->stack; | ||
127 | stack_start.bss_start = 0; /* don't clear bss for secondary cpus */ | ||
128 | stack_start.start_kernel_fn = start_secondary; | ||
123 | 129 | ||
124 | smp_store_cpu_info(cpu); | 130 | flush_cache_all(); |
125 | 131 | ||
126 | __smp_slave_init(cpu); | 132 | plat_start_cpu(cpu, (unsigned long)_stext); |
127 | preempt_disable(); | ||
128 | per_cpu_trap_init(); | ||
129 | |||
130 | atomic_inc(&cpus_booted); | ||
131 | 133 | ||
132 | cpu_idle(); | 134 | timeout = jiffies + HZ; |
133 | return 0; | 135 | while (time_before(jiffies, timeout)) { |
136 | if (cpu_online(cpu)) | ||
137 | break; | ||
138 | |||
139 | udelay(10); | ||
140 | } | ||
141 | |||
142 | if (cpu_online(cpu)) | ||
143 | return 0; | ||
144 | |||
145 | return -ENOENT; | ||
134 | } | 146 | } |
135 | 147 | ||
136 | void __init smp_cpus_done(unsigned int max_cpus) | 148 | void __init smp_cpus_done(unsigned int max_cpus) |
137 | { | 149 | { |
138 | smp_mb(); | 150 | unsigned long bogosum = 0; |
151 | int cpu; | ||
152 | |||
153 | for_each_online_cpu(cpu) | ||
154 | bogosum += cpu_data[cpu].loops_per_jiffy; | ||
155 | |||
156 | printk(KERN_INFO "SMP: Total of %d processors activated " | ||
157 | "(%lu.%02lu BogoMIPS).\n", num_online_cpus(), | ||
158 | bogosum / (500000/HZ), | ||
159 | (bogosum / (5000/HZ)) % 100); | ||
139 | } | 160 | } |
140 | 161 | ||
141 | void smp_send_reschedule(int cpu) | 162 | void smp_send_reschedule(int cpu) |
142 | { | 163 | { |
143 | __smp_send_ipi(cpu, SMP_MSG_RESCHEDULE); | 164 | plat_send_ipi(cpu, SMP_MSG_RESCHEDULE); |
144 | } | 165 | } |
145 | 166 | ||
146 | static void stop_this_cpu(void *unused) | 167 | static void stop_this_cpu(void *unused) |
@@ -157,7 +178,6 @@ void smp_send_stop(void) | |||
157 | smp_call_function(stop_this_cpu, 0, 1, 0); | 178 | smp_call_function(stop_this_cpu, 0, 1, 0); |
158 | } | 179 | } |
159 | 180 | ||
160 | |||
161 | struct smp_fn_call_struct smp_fn_call = { | 181 | struct smp_fn_call_struct smp_fn_call = { |
162 | .lock = SPIN_LOCK_UNLOCKED, | 182 | .lock = SPIN_LOCK_UNLOCKED, |
163 | .finished = ATOMIC_INIT(0), | 183 | .finished = ATOMIC_INIT(0), |
@@ -175,9 +195,6 @@ int smp_call_function(void (*func)(void *info), void *info, int retry, int wait) | |||
175 | unsigned int nr_cpus = atomic_read(&cpus_booted); | 195 | unsigned int nr_cpus = atomic_read(&cpus_booted); |
176 | int i; | 196 | int i; |
177 | 197 | ||
178 | if (nr_cpus < 2) | ||
179 | return 0; | ||
180 | |||
181 | /* Can deadlock when called with interrupts disabled */ | 198 | /* Can deadlock when called with interrupts disabled */ |
182 | WARN_ON(irqs_disabled()); | 199 | WARN_ON(irqs_disabled()); |
183 | 200 | ||
@@ -189,7 +206,7 @@ int smp_call_function(void (*func)(void *info), void *info, int retry, int wait) | |||
189 | 206 | ||
190 | for (i = 0; i < nr_cpus; i++) | 207 | for (i = 0; i < nr_cpus; i++) |
191 | if (i != smp_processor_id()) | 208 | if (i != smp_processor_id()) |
192 | __smp_call_function(i); | 209 | plat_send_ipi(i, SMP_MSG_FUNCTION); |
193 | 210 | ||
194 | if (wait) | 211 | if (wait) |
195 | while (atomic_read(&smp_fn_call.finished) != (nr_cpus - 1)); | 212 | while (atomic_read(&smp_fn_call.finished) != (nr_cpus - 1)); |