GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / arch / mips / kernel / smp-cmp.c
blob746d357117bbabf88c535c8ad3817cbf024ea980
1 /*
2 * This program is free software; you can distribute it and/or modify it
3 * under the terms of the GNU General Public License (Version 2) as
4 * published by the Free Software Foundation.
6 * This program is distributed in the hope it will be useful, but WITHOUT
7 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
8 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
9 * for more details.
11 * You should have received a copy of the GNU General Public License along
12 * with this program; if not, write to the Free Software Foundation, Inc.,
13 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
15 * Copyright (C) 2007, 2011 MIPS Technologies, Inc.
16 * Chris Dearman (chris@mips.com)
17 * Steven J. Hill (sjhill@mips.com)
20 #undef DEBUG
22 #include <linux/cpu.h>
23 #include <linux/kernel.h>
24 #include <linux/sched.h>
25 #include <linux/smp.h>
26 #include <linux/cpumask.h>
27 #include <linux/interrupt.h>
28 #include <linux/compiler.h>
30 #include <asm/atomic.h>
31 #include <asm/cacheflush.h>
32 #include <asm/cpu.h>
33 #include <asm/processor.h>
34 #include <asm/system.h>
35 #include <asm/hardirq.h>
36 #include <asm/mmu_context.h>
37 #include <asm/smp.h>
38 #include <asm/time.h>
39 #include <asm/mipsregs.h>
40 #include <asm/mipsmtregs.h>
41 #include <asm/mips_mt.h>
42 #include <asm/amon.h>
43 #include <asm/gic.h>
45 static void ipi_call_function(unsigned int cpu)
47 pr_debug("CPU%d: %s cpu %d status %08x\n",
48 smp_processor_id(), __func__, cpu, read_c0_status());
50 gic_send_ipi(plat_ipi_call_int_xlate(cpu));
54 static void ipi_resched(unsigned int cpu)
56 pr_debug("CPU%d: %s cpu %d status %08x\n",
57 smp_processor_id(), __func__, cpu, read_c0_status());
59 gic_send_ipi(plat_ipi_resched_int_xlate(cpu));
62 void cmp_send_ipi_single(int cpu, unsigned int action)
64 unsigned long flags;
66 local_irq_save(flags);
68 switch (action) {
69 case SMP_CALL_FUNCTION:
70 ipi_call_function(cpu);
71 break;
73 case SMP_RESCHEDULE_YOURSELF:
74 ipi_resched(cpu);
75 break;
78 local_irq_restore(flags);
81 static void cmp_send_ipi_mask(const struct cpumask *mask, unsigned int action)
83 unsigned int i;
85 for_each_cpu(i, mask)
86 cmp_send_ipi_single(i, action);
89 static void __cpuinit cmp_init_secondary(void)
91 struct cpuinfo_mips *c = &current_cpu_data;
93 /* Assume GIC is present */
94 change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP6 |
95 STATUSF_IP7);
97 /* Enable per-cpu interrupts: platform specific */
99 c->core = (read_c0_ebase() >> 1) & 0xff;
100 #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC)
101 c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE;
102 #endif
103 #ifdef CONFIG_MIPS_MT_SMTC
104 c->tc_id = (read_c0_tcbind() >> TCBIND_CURTC_SHIFT) & TCBIND_CURTC;
105 #endif
108 static void __cpuinit cmp_smp_finish(void)
110 pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__);
112 /* Arrange for a clock interrupt immediately */
113 write_c0_compare(read_c0_count() + 200);
115 #ifdef CONFIG_MIPS_MT_FPAFF
116 /* If we have an FPU, enroll ourselves in the FPU-full mask */
117 if (cpu_has_fpu)
118 cpu_set(smp_processor_id(), mt_fpu_cpumask);
119 #endif /* CONFIG_MIPS_MT_FPAFF */
121 local_irq_enable();
124 static void __cpuinit cmp_cpus_done(void)
126 pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__);
130 * Setup the PC, SP, and GP of a secondary processor and start it running
131 * smp_bootstrap is the place to resume from
132 * __KSTK_TOS(idle) is apparently the stack pointer
133 * (unsigned long)idle->thread_info the gp
135 static void __cpuinit cmp_boot_secondary(int cpu, struct task_struct *idle)
137 struct thread_info *gp = task_thread_info(idle);
138 unsigned long sp = __KSTK_TOS(idle);
139 unsigned long pc = (unsigned long)&smp_bootstrap;
140 unsigned long a0 = 0;
142 pr_debug("SMPCMP: CPU%d: %s cpu %d\n", smp_processor_id(),
143 __func__, cpu);
146 amon_cpu_start(cpu, pc, sp, (unsigned long)gp, a0);
150 * Common setup before any secondaries are started
152 void __init cmp_smp_setup(void)
154 int i;
155 int ncpu = 0;
157 pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__);
159 #ifdef CONFIG_MIPS_MT_FPAFF
160 /* If we have an FPU, enroll ourselves in the FPU-full mask */
161 if (cpu_has_fpu)
162 cpu_set(0, mt_fpu_cpumask);
163 #endif /* CONFIG_MIPS_MT_FPAFF */
165 for (i = 1; i < NR_CPUS; i++) {
166 if (amon_cpu_avail(i)) {
167 set_cpu_possible(i, true);
168 __cpu_number_map[i] = ++ncpu;
169 __cpu_logical_map[ncpu] = i;
172 cpu_present_map = cpu_possible_map;
174 if (cpu_has_mipsmt) {
175 unsigned int nvpe, mvpconf0 = read_c0_mvpconf0();
177 nvpe = ((mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1;
178 smp_num_siblings = nvpe;
180 pr_info("Detected %i available secondary CPU(s)\n", ncpu);
183 void __init cmp_prepare_cpus(unsigned int max_cpus)
185 pr_debug("SMPCMP: CPU%d: %s max_cpus=%d\n",
186 smp_processor_id(), __func__, max_cpus);
188 mips_mt_set_cpuoptions();
191 #ifdef CONFIG_HOTPLUG_CPU
193 /* State of each CPU. */
194 DEFINE_PER_CPU(int, cpu_state);
196 extern void fixup_irqs(void);
198 static DEFINE_SPINLOCK(smp_reserve_lock);
200 static int cmp_cpu_disable(void)
202 unsigned int cpu = smp_processor_id();
204 if (cpu == 0)
205 return -EBUSY;
207 spin_lock(&smp_reserve_lock);
209 cpu_clear(cpu, cpu_online_map);
210 cpu_clear(cpu, cpu_callin_map);
211 local_irq_disable();
212 fixup_irqs();
213 local_irq_enable();
215 flush_cache_all();
216 local_flush_tlb_all();
218 spin_unlock(&smp_reserve_lock);
220 return 0;
223 static void cmp_cpu_die(unsigned int cpu)
225 while (per_cpu(cpu_state, cpu) != CPU_DEAD)
226 cpu_relax();
228 * If all of the CPU's on the other core are now disabled
229 * the core can be powered down
233 void play_dead(void)
235 int coreid = smp_processor_id();
237 idle_task_exit();
239 per_cpu(cpu_state, coreid) = CPU_DEAD;
242 * This CPU is now inactive. Other CPU's (VPE's) on the
243 * same core may still be active
245 amon_cpu_dead(); /* This will not return */
248 static int __cpuinit cmp_cpu_callback(struct notifier_block *nfb,
249 unsigned long action, void *hcpu)
251 unsigned int cpu = (unsigned long)hcpu;
253 switch (action) {
254 case CPU_UP_PREPARE:
255 pr_debug("CPU%d: prepare\n", cpu);
256 break;
257 case CPU_ONLINE:
258 pr_debug("CPU%d: online\n", cpu);
259 break;
260 case CPU_DEAD:
261 pr_debug("CPU%d: dead\n", cpu);
262 break;
265 return NOTIFY_OK;
268 static struct notifier_block __cpuinitdata cmp_cpu_notifier = {
269 .notifier_call = cmp_cpu_callback,
272 static int __cpuinit register_cmp_notifier(void)
274 register_hotcpu_notifier(&cmp_cpu_notifier);
276 return 0;
279 late_initcall(register_cmp_notifier);
281 #endif /* CONFIG_HOTPLUG_CPU */
284 struct plat_smp_ops cmp_smp_ops = {
285 .send_ipi_single = cmp_send_ipi_single,
286 .send_ipi_mask = cmp_send_ipi_mask,
287 .init_secondary = cmp_init_secondary,
288 .smp_finish = cmp_smp_finish,
289 .cpus_done = cmp_cpus_done,
290 .boot_secondary = cmp_boot_secondary,
291 .smp_setup = cmp_smp_setup,
292 .prepare_cpus = cmp_prepare_cpus,
293 #ifdef CONFIG_HOTPLUG_CPU
294 .cpu_disable = cmp_cpu_disable,
295 .cpu_die = cmp_cpu_die,
296 #endif