Blame view

arch/mips/kernel/smp-mt.c 7.15 KB
340ee4b98   Ralf Baechle   Virtual SMP suppo...
1
  /*
340ee4b98   Ralf Baechle   Virtual SMP suppo...
2
3
4
5
6
7
8
9
10
11
12
13
14
   *  This program is free software; you can distribute it and/or modify it
   *  under the terms of the GNU General Public License (Version 2) as
   *  published by the Free Software Foundation.
   *
   *  This program is distributed in the hope it will be useful, but WITHOUT
   *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   *  for more details.
   *
   *  You should have received a copy of the GNU General Public License along
   *  with this program; if not, write to the Free Software Foundation, Inc.,
   *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
   *
41c594ab6   Ralf Baechle   [MIPS] MT: Improv...
15
16
17
18
   * Copyright (C) 2004, 05, 06 MIPS Technologies, Inc.
   *    Elizabeth Clarke (beth@mips.com)
   *    Ralf Baechle (ralf@linux-mips.org)
   * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
340ee4b98   Ralf Baechle   Virtual SMP suppo...
19
20
21
22
23
24
   */
  #include <linux/kernel.h>
  #include <linux/sched.h>
  #include <linux/cpumask.h>
  #include <linux/interrupt.h>
  #include <linux/compiler.h>
0ab7aefc4   Ralf Baechle   [MIPS] MT: Schedu...
25
  #include <linux/smp.h>
340ee4b98   Ralf Baechle   Virtual SMP suppo...
26

60063497a   Arun Sharma   atomic: use <linu...
27
  #include <linux/atomic.h>
41c594ab6   Ralf Baechle   [MIPS] MT: Improv...
28
  #include <asm/cacheflush.h>
340ee4b98   Ralf Baechle   Virtual SMP suppo...
29
30
31
32
33
  #include <asm/cpu.h>
  #include <asm/processor.h>
  #include <asm/system.h>
  #include <asm/hardirq.h>
  #include <asm/mmu_context.h>
340ee4b98   Ralf Baechle   Virtual SMP suppo...
34
35
36
  #include <asm/time.h>
  #include <asm/mipsregs.h>
  #include <asm/mipsmtregs.h>
41c594ab6   Ralf Baechle   [MIPS] MT: Improv...
37
  #include <asm/mips_mt.h>
340ee4b98   Ralf Baechle   Virtual SMP suppo...
38

39b8d5254   Ralf Baechle   [MIPS] Add suppor...
39
  static void __init smvp_copy_vpe_config(void)
781b0f8d4   Ralf Baechle   [MIPS] VSMP: Fix ...
40
41
42
43
44
45
46
47
48
49
50
51
  {
  	write_vpe_c0_status(
  		(read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0);
  
  	/* set config to be the same as vpe0, particularly kseg0 coherency alg */
  	write_vpe_c0_config( read_c0_config());
  
  	/* make sure there are no software interrupts pending */
  	write_vpe_c0_cause(0);
  
  	/* Propagate Config7 */
  	write_vpe_c0_config7(read_c0_config7());
70e46f48c   Ralf Baechle   [MIPS] VSMP: Sync...
52
53
  
  	write_vpe_c0_count(read_c0_count());
781b0f8d4   Ralf Baechle   [MIPS] VSMP: Fix ...
54
  }
39b8d5254   Ralf Baechle   [MIPS] Add suppor...
55
  static unsigned int __init smvp_vpe_init(unsigned int tc, unsigned int mvpconf0,
781b0f8d4   Ralf Baechle   [MIPS] VSMP: Fix ...
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  	unsigned int ncpu)
  {
  	if (tc > ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT))
  		return ncpu;
  
  	/* Deactivate all but VPE 0 */
  	if (tc != 0) {
  		unsigned long tmp = read_vpe_c0_vpeconf0();
  
  		tmp &= ~VPECONF0_VPA;
  
  		/* master VPE */
  		tmp |= VPECONF0_MVP;
  		write_vpe_c0_vpeconf0(tmp);
  
  		/* Record this as available CPU */
4037ac6e2   Rusty Russell   cpumask: Use acce...
72
  		set_cpu_possible(tc, true);
781b0f8d4   Ralf Baechle   [MIPS] VSMP: Fix ...
73
74
75
76
77
78
79
80
  		__cpu_number_map[tc]	= ++ncpu;
  		__cpu_logical_map[ncpu]	= tc;
  	}
  
  	/* Disable multi-threading with TC's */
  	write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);
  
  	if (tc != 0)
39b8d5254   Ralf Baechle   [MIPS] Add suppor...
81
  		smvp_copy_vpe_config();
781b0f8d4   Ralf Baechle   [MIPS] VSMP: Fix ...
82
83
84
  
  	return ncpu;
  }
39b8d5254   Ralf Baechle   [MIPS] Add suppor...
85
  static void __init smvp_tc_init(unsigned int tc, unsigned int mvpconf0)
781b0f8d4   Ralf Baechle   [MIPS] VSMP: Fix ...
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
  {
  	unsigned long tmp;
  
  	if (!tc)
  		return;
  
  	/* bind a TC to each VPE, May as well put all excess TC's
  	   on the last VPE */
  	if (tc >= (((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)+1))
  		write_tc_c0_tcbind(read_tc_c0_tcbind() | ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT));
  	else {
  		write_tc_c0_tcbind(read_tc_c0_tcbind() | tc);
  
  		/* and set XTC */
  		write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | (tc << VPECONF0_XTC_SHIFT));
  	}
  
  	tmp = read_tc_c0_tcstatus();
  
  	/* mark not allocated and not dynamically allocatable */
  	tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
  	tmp |= TCSTATUS_IXMT;		/* interrupt exempt */
  	write_tc_c0_tcstatus(tmp);
  
  	write_tc_c0_tchalt(TCHALT_H);
  }
87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
112
  static void vsmp_send_ipi_single(int cpu, unsigned int action)
340ee4b98   Ralf Baechle   Virtual SMP suppo...
113
  {
87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
114
115
116
  	int i;
  	unsigned long flags;
  	int vpflags;
340ee4b98   Ralf Baechle   Virtual SMP suppo...
117

87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
118
  	local_irq_save(flags);
340ee4b98   Ralf Baechle   Virtual SMP suppo...
119

25985edce   Lucas De Marchi   Fix common misspe...
120
  	vpflags = dvpe();	/* can't access the other CPU's registers whilst MVPE enabled */
340ee4b98   Ralf Baechle   Virtual SMP suppo...
121

87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
122
123
124
125
  	switch (action) {
  	case SMP_CALL_FUNCTION:
  		i = C_SW1;
  		break;
340ee4b98   Ralf Baechle   Virtual SMP suppo...
126

87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
127
128
129
130
131
  	case SMP_RESCHEDULE_YOURSELF:
  	default:
  		i = C_SW0;
  		break;
  	}
340ee4b98   Ralf Baechle   Virtual SMP suppo...
132

87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
133
134
135
136
  	/* 1:1 mapping of vpe and tc... */
  	settc(cpu);
  	write_vpe_c0_cause(read_vpe_c0_cause() | i);
  	evpe(vpflags);
0ab7aefc4   Ralf Baechle   [MIPS] MT: Schedu...
137

87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
138
139
  	local_irq_restore(flags);
  }
340ee4b98   Ralf Baechle   Virtual SMP suppo...
140

48a048fed   Rusty Russell   cpumask: arch_sen...
141
  static void vsmp_send_ipi_mask(const struct cpumask *mask, unsigned int action)
87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
142
143
  {
  	unsigned int i;
340ee4b98   Ralf Baechle   Virtual SMP suppo...
144

48a048fed   Rusty Russell   cpumask: arch_sen...
145
  	for_each_cpu(i, mask)
87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
146
147
  		vsmp_send_ipi_single(i, action);
  }
340ee4b98   Ralf Baechle   Virtual SMP suppo...
148

87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
149
150
  static void __cpuinit vsmp_init_secondary(void)
  {
39b8d5254   Ralf Baechle   [MIPS] Add suppor...
151
  	extern int gic_present;
340ee4b98   Ralf Baechle   Virtual SMP suppo...
152

d002aaadf   Ralf Baechle   MIPS: MT: Fix typ...
153
  	/* This is Malta specific: IPI,performance and timer interrupts */
39b8d5254   Ralf Baechle   [MIPS] Add suppor...
154
155
156
157
158
159
  	if (gic_present)
  		change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 |
  					 STATUSF_IP6 | STATUSF_IP7);
  	else
  		change_c0_status(ST0_IM, STATUSF_IP0 | STATUSF_IP1 |
  					 STATUSF_IP6 | STATUSF_IP7);
41c594ab6   Ralf Baechle   [MIPS] MT: Improv...
160
  }
340ee4b98   Ralf Baechle   Virtual SMP suppo...
161

87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
162
  static void __cpuinit vsmp_smp_finish(void)
41c594ab6   Ralf Baechle   [MIPS] MT: Improv...
163
  {
39b8d5254   Ralf Baechle   [MIPS] Add suppor...
164
  	/* CDFIXME: remove this? */
87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
165
  	write_c0_compare(read_c0_count() + (8* mips_hpt_frequency/HZ));
340ee4b98   Ralf Baechle   Virtual SMP suppo...
166

87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
167
168
169
170
171
  #ifdef CONFIG_MIPS_MT_FPAFF
  	/* If we have an FPU, enroll ourselves in the FPU-full mask */
  	if (cpu_has_fpu)
  		cpu_set(smp_processor_id(), mt_fpu_cpumask);
  #endif /* CONFIG_MIPS_MT_FPAFF */
340ee4b98   Ralf Baechle   Virtual SMP suppo...
172

87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
173
174
  	local_irq_enable();
  }
340ee4b98   Ralf Baechle   Virtual SMP suppo...
175

87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
176
177
  static void vsmp_cpus_done(void)
  {
340ee4b98   Ralf Baechle   Virtual SMP suppo...
178
179
180
181
182
183
184
185
186
187
  }
  
  /*
   * Setup the PC, SP, and GP of a secondary processor and start it
   * running!
   * smp_bootstrap is the place to resume from
   * __KSTK_TOS(idle) is apparently the stack pointer
   * (unsigned long)idle->thread_info the gp
   * assumes a 1:1 mapping of TC => VPE
   */
87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
188
  static void __cpuinit vsmp_boot_secondary(int cpu, struct task_struct *idle)
340ee4b98   Ralf Baechle   Virtual SMP suppo...
189
  {
dc8f6029c   Al Viro   [PATCH] mips: tas...
190
  	struct thread_info *gp = task_thread_info(idle);
340ee4b98   Ralf Baechle   Virtual SMP suppo...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
  	dvpe();
  	set_c0_mvpcontrol(MVPCONTROL_VPC);
  
  	settc(cpu);
  
  	/* restart */
  	write_tc_c0_tcrestart((unsigned long)&smp_bootstrap);
  
  	/* enable the tc this vpe/cpu will be running */
  	write_tc_c0_tcstatus((read_tc_c0_tcstatus() & ~TCSTATUS_IXMT) | TCSTATUS_A);
  
  	write_tc_c0_tchalt(0);
  
  	/* enable the VPE */
  	write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
  
  	/* stack pointer */
  	write_tc_gpr_sp( __KSTK_TOS(idle));
  
  	/* global pointer */
dc8f6029c   Al Viro   [PATCH] mips: tas...
211
  	write_tc_gpr_gp((unsigned long)gp);
340ee4b98   Ralf Baechle   Virtual SMP suppo...
212

41c594ab6   Ralf Baechle   [MIPS] MT: Improv...
213
214
  	flush_icache_range((unsigned long)gp,
  	                   (unsigned long)(gp + sizeof(struct thread_info)));
340ee4b98   Ralf Baechle   Virtual SMP suppo...
215
216
217
218
219
220
  
  	/* finally out of configuration and into chaos */
  	clear_c0_mvpcontrol(MVPCONTROL_VPC);
  
  	evpe(EVPE_ENABLE);
  }
87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
221
222
223
  /*
   * Common setup before any secondaries are started
   * Make sure all CPU's are in a sensible state before we boot any of the
39b8d5254   Ralf Baechle   [MIPS] Add suppor...
224
   * secondaries
87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
225
226
   */
  static void __init vsmp_smp_setup(void)
340ee4b98   Ralf Baechle   Virtual SMP suppo...
227
  {
87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
228
229
  	unsigned int mvpconf0, ntc, tc, ncpu = 0;
  	unsigned int nvpe;
340ee4b98   Ralf Baechle   Virtual SMP suppo...
230

f088fc84f   Ralf Baechle   [MIPS] FPU affini...
231
232
233
  #ifdef CONFIG_MIPS_MT_FPAFF
  	/* If we have an FPU, enroll ourselves in the FPU-full mask */
  	if (cpu_has_fpu)
87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
234
  		cpu_set(0, mt_fpu_cpumask);
f088fc84f   Ralf Baechle   [MIPS] FPU affini...
235
  #endif /* CONFIG_MIPS_MT_FPAFF */
87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
236
237
  	if (!cpu_has_mipsmt)
  		return;
f088fc84f   Ralf Baechle   [MIPS] FPU affini...
238

87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
239
240
241
  	/* disable MT so we can configure */
  	dvpe();
  	dmt();
340ee4b98   Ralf Baechle   Virtual SMP suppo...
242

87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
243
244
  	/* Put MVPE's into 'configuration state' */
  	set_c0_mvpcontrol(MVPCONTROL_VPC);
340ee4b98   Ralf Baechle   Virtual SMP suppo...
245

87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
246
247
  	mvpconf0 = read_c0_mvpconf0();
  	ntc = (mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT;
340ee4b98   Ralf Baechle   Virtual SMP suppo...
248

87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
249
250
  	nvpe = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
  	smp_num_siblings = nvpe;
340ee4b98   Ralf Baechle   Virtual SMP suppo...
251

87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
252
253
254
255
  	/* we'll always have more TC's than VPE's, so loop setting everything
  	   to a sensible state */
  	for (tc = 0; tc <= ntc; tc++) {
  		settc(tc);
340ee4b98   Ralf Baechle   Virtual SMP suppo...
256

39b8d5254   Ralf Baechle   [MIPS] Add suppor...
257
258
  		smvp_tc_init(tc, mvpconf0);
  		ncpu = smvp_vpe_init(tc, mvpconf0, ncpu);
87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
259
  	}
340ee4b98   Ralf Baechle   Virtual SMP suppo...
260

87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
261
262
263
264
265
266
267
268
269
270
271
272
  	/* Release config state */
  	clear_c0_mvpcontrol(MVPCONTROL_VPC);
  
  	/* We'll wait until starting the secondaries before starting MVPE */
  
  	printk(KERN_INFO "Detected %i available secondary CPU(s)
  ", ncpu);
  }
  
  static void __init vsmp_prepare_cpus(unsigned int max_cpus)
  {
  	mips_mt_set_cpuoptions();
340ee4b98   Ralf Baechle   Virtual SMP suppo...
273
  }
87353d8ac   Ralf Baechle   [MIPS] SMP: Call ...
274
275
276
277
278
279
280
281
282
283
284
  
  struct plat_smp_ops vsmp_smp_ops = {
  	.send_ipi_single	= vsmp_send_ipi_single,
  	.send_ipi_mask		= vsmp_send_ipi_mask,
  	.init_secondary		= vsmp_init_secondary,
  	.smp_finish		= vsmp_smp_finish,
  	.cpus_done		= vsmp_cpus_done,
  	.boot_secondary		= vsmp_boot_secondary,
  	.smp_setup		= vsmp_smp_setup,
  	.prepare_cpus		= vsmp_prepare_cpus,
  };