aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2007-09-21 05:32:32 -0400
committerPaul Mundt <lethal@linux-sh.org>2007-09-21 05:32:32 -0400
commitaba1030a7e529ec9fe47a8cfc06d12a39180fa71 (patch)
treea28de7f7b89610246fddf488f042b58c66101b95 /arch/sh/kernel
parentf18d533e3cd476aedf41fe1e6e9dc3e0a2446bba (diff)
sh: Bring SMP support back from the dead.
There was a very preliminary bunch of SMP code scattered around for the SH7604 microcontrollers from way back when, and it has mostly suffered bitrot since then. With the tree already having been slowly getting prepped for SMP, this plugs in most of the remaining platform-independent bits. Signed-off-by: Magnus Damm <damm@igel.co.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r--arch/sh/kernel/cpu/init.c16
-rw-r--r--arch/sh/kernel/head.S18
-rw-r--r--arch/sh/kernel/smp.c167
-rw-r--r--arch/sh/kernel/traps.c5
4 files changed, 118 insertions, 88 deletions
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index fdc245b7b043..c217c4bf0085 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -22,6 +22,7 @@
22#include <asm/cache.h> 22#include <asm/cache.h>
23#include <asm/io.h> 23#include <asm/io.h>
24#include <asm/ubc.h> 24#include <asm/ubc.h>
25#include <asm/smp.h>
25 26
26/* 27/*
27 * Generic wrapper for command line arguments to disable on-chip 28 * Generic wrapper for command line arguments to disable on-chip
@@ -216,8 +217,11 @@ static void __init dsp_init(void)
216 * Each processor family is still responsible for doing its own probing 217 * Each processor family is still responsible for doing its own probing
217 * and cache configuration in detect_cpu_and_cache_system(). 218 * and cache configuration in detect_cpu_and_cache_system().
218 */ 219 */
219asmlinkage void __init sh_cpu_init(void) 220
221asmlinkage void __cpuinit sh_cpu_init(void)
220{ 222{
223 current_thread_info()->cpu = hard_smp_processor_id();
224
221 /* First, probe the CPU */ 225 /* First, probe the CPU */
222 detect_cpu_and_cache_system(); 226 detect_cpu_and_cache_system();
223 227
@@ -227,9 +231,10 @@ asmlinkage void __init sh_cpu_init(void)
227 /* Init the cache */ 231 /* Init the cache */
228 cache_init(); 232 cache_init();
229 233
230 shm_align_mask = max_t(unsigned long, 234 if (raw_smp_processor_id() == 0)
231 current_cpu_data.dcache.way_size - 1, 235 shm_align_mask = max_t(unsigned long,
232 PAGE_SIZE - 1); 236 current_cpu_data.dcache.way_size - 1,
237 PAGE_SIZE - 1);
233 238
234 /* Disable the FPU */ 239 /* Disable the FPU */
235 if (fpu_disabled) { 240 if (fpu_disabled) {
@@ -268,6 +273,7 @@ asmlinkage void __init sh_cpu_init(void)
268 * like PTRACE_SINGLESTEP or doing hardware watchpoints in GDB. So .. 273 * like PTRACE_SINGLESTEP or doing hardware watchpoints in GDB. So ..
269 * we wake it up and hope that all is well. 274 * we wake it up and hope that all is well.
270 */ 275 */
271 ubc_wakeup(); 276 if (raw_smp_processor_id() == 0)
277 ubc_wakeup();
272 speculative_execution_init(); 278 speculative_execution_init();
273} 279}
diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head.S
index 0bccc0ca5a0f..3338239717f1 100644
--- a/arch/sh/kernel/head.S
+++ b/arch/sh/kernel/head.S
@@ -54,8 +54,8 @@ ENTRY(_stext)
54 mov.l 1f, r0 ! MD=1, RB=0, BL=0, IMASK=0xF 54 mov.l 1f, r0 ! MD=1, RB=0, BL=0, IMASK=0xF
55 ldc r0, sr 55 ldc r0, sr
56 ! Initialize global interrupt mask 56 ! Initialize global interrupt mask
57 mov #0, r0
58#ifdef CONFIG_CPU_HAS_SR_RB 57#ifdef CONFIG_CPU_HAS_SR_RB
58 mov #0, r0
59 ldc r0, r6_bank 59 ldc r0, r6_bank
60#endif 60#endif
61 61
@@ -72,15 +72,18 @@ ENTRY(_stext)
72 ! 72 !
73 mov.l 2f, r0 73 mov.l 2f, r0
74 mov r0, r15 ! Set initial r15 (stack pointer) 74 mov r0, r15 ! Set initial r15 (stack pointer)
75 mov #(THREAD_SIZE >> 10), r1
76 shll8 r1 ! r1 = THREAD_SIZE
77 shll2 r1
78 sub r1, r0 !
79#ifdef CONFIG_CPU_HAS_SR_RB 75#ifdef CONFIG_CPU_HAS_SR_RB
76 mov.l 7f, r0
80 ldc r0, r7_bank ! ... and initial thread_info 77 ldc r0, r7_bank ! ... and initial thread_info
81#endif 78#endif
82 79
83 ! Clear BSS area 80 ! Clear BSS area
81#ifdef CONFIG_SMP
82 mov.l 3f, r0
83 cmp/eq #0, r0 ! skip clear if set to zero
84 bt 10f
85#endif
86
84 mov.l 3f, r1 87 mov.l 3f, r1
85 add #4, r1 88 add #4, r1
86 mov.l 4f, r2 89 mov.l 4f, r2
@@ -89,13 +92,14 @@ ENTRY(_stext)
89 bf/s 9b ! while (r1 < r2) 92 bf/s 9b ! while (r1 < r2)
90 mov.l r0,@-r2 93 mov.l r0,@-r2
91 94
9510:
92 ! Additional CPU initialization 96 ! Additional CPU initialization
93 mov.l 6f, r0 97 mov.l 6f, r0
94 jsr @r0 98 jsr @r0
95 nop 99 nop
96 100
97 SYNCO() ! Wait for pending instructions.. 101 SYNCO() ! Wait for pending instructions..
98 102
99 ! Start kernel 103 ! Start kernel
100 mov.l 5f, r0 104 mov.l 5f, r0
101 jmp @r0 105 jmp @r0
@@ -107,8 +111,10 @@ ENTRY(_stext)
107#else 111#else
1081: .long 0x400080F0 ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF 1121: .long 0x400080F0 ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF
109#endif 113#endif
114ENTRY(stack_start)
1102: .long init_thread_union+THREAD_SIZE 1152: .long init_thread_union+THREAD_SIZE
1113: .long __bss_start 1163: .long __bss_start
1124: .long _end 1174: .long _end
1135: .long start_kernel 1185: .long start_kernel
1146: .long sh_cpu_init 1196: .long sh_cpu_init
1207: .long init_thread_union
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/* 30int __cpu_number_map[NR_CPUS]; /* Map physical to logical */
35 * This was written with the Sega Saturn (SMP SH-2 7604) in mind, 31int __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 */
39struct sh_cpuinfo cpu_data[NR_CPUS];
40
41extern void per_cpu_trap_init(void);
42 32
43cpumask_t cpu_possible_map; 33cpumask_t cpu_possible_map;
44EXPORT_SYMBOL(cpu_possible_map); 34EXPORT_SYMBOL(cpu_possible_map);
45 35
46cpumask_t cpu_online_map; 36cpumask_t cpu_online_map;
47EXPORT_SYMBOL(cpu_online_map); 37EXPORT_SYMBOL(cpu_online_map);
48static atomic_t cpus_booted = ATOMIC_INIT(0);
49
50/* These are defined by the board-specific code. */
51 38
52/* 39static 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 */
57void __smp_send_ipi(unsigned int cpu, unsigned int action);
58
59/*
60 * Find the number of available processors
61 */
62unsigned int __smp_probe_cpus(void);
63
64/*
65 * Start a particular processor
66 */
67void __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
74static inline void __init smp_store_cpu_info(unsigned int cpu) 46static 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
79void __init smp_prepare_cpus(unsigned int max_cpus) 53void __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
91void __devinit smp_prepare_boot_cpu(void) 66void __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
99int __cpu_up(unsigned int cpu) 77asmlinkage 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
115int start_secondary(void *unused) 104extern 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
113int __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
136void __init smp_cpus_done(unsigned int max_cpus) 148void __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
141void smp_send_reschedule(int cpu) 162void 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
146static void stop_this_cpu(void *unused) 167static 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
161struct smp_fn_call_struct smp_fn_call = { 181struct 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));
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index 67015044d74a..dcb46e71da1c 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -807,12 +807,13 @@ static inline void __init gdb_vbr_init(void)
807} 807}
808#endif 808#endif
809 809
810void __init per_cpu_trap_init(void) 810void __cpuinit per_cpu_trap_init(void)
811{ 811{
812 extern void *vbr_base; 812 extern void *vbr_base;
813 813
814#ifdef CONFIG_SH_STANDARD_BIOS 814#ifdef CONFIG_SH_STANDARD_BIOS
815 gdb_vbr_init(); 815 if (raw_smp_processor_id() == 0)
816 gdb_vbr_init();
816#endif 817#endif
817 818
818 /* NOTE: The VBR value should be at P1 819 /* NOTE: The VBR value should be at P1