aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/smp.c
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/smp.c
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/smp.c')
-rw-r--r--arch/sh/kernel/smp.c167
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/* 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));