aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2005-08-17 13:44:08 -0400
committerRalf Baechle <ralf@linux-mips.org>2005-10-29 14:32:10 -0400
commit340ee4b98c0543b5632cac975a7449a2d28762d8 (patch)
tree94b7315d53d6eadd145c8691f0a9925f5ae389f5 /arch
parentd03d0a57754cb820d318d2234c60b728eb38a94d (diff)
Virtual SMP support for the 34K.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/mips/Kconfig12
-rw-r--r--arch/mips/kernel/Makefile2
-rw-r--r--arch/mips/kernel/genex.S1
-rw-r--r--arch/mips/kernel/smp_mt.c366
-rw-r--r--arch/mips/kernel/traps.c14
-rw-r--r--arch/mips/kernel/vpe.c15
-rw-r--r--arch/mips/mips-boards/generic/time.c51
7 files changed, 448 insertions, 13 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 5af30d385aca..8746e1b1621b 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1344,6 +1344,14 @@ config CPU_HAS_PREFETCH
1344config MIPS_MT 1344config MIPS_MT
1345 bool "Enable MIPS MT" 1345 bool "Enable MIPS MT"
1346 1346
1347choice
1348 prompt "MIPS MT options"
1349 depends on MIPS_MT
1350
1351config MIPS_MT_SMP
1352 bool "Use 1 TC on each available VPE for SMP"
1353 select SMP
1354
1347config MIPS_VPE_LOADER 1355config MIPS_VPE_LOADER
1348 bool "VPE loader support." 1356 bool "VPE loader support."
1349 depends on MIPS_MT 1357 depends on MIPS_MT
@@ -1351,6 +1359,8 @@ config MIPS_VPE_LOADER
1351 Includes a loader for loading an elf relocatable object 1359 Includes a loader for loading an elf relocatable object
1352 onto another VPE and running it. 1360 onto another VPE and running it.
1353 1361
1362endchoice
1363
1354config MIPS_VPE_LOADER_TOM 1364config MIPS_VPE_LOADER_TOM
1355 bool "Load VPE program into memory hidden from linux" 1365 bool "Load VPE program into memory hidden from linux"
1356 depends on MIPS_VPE_LOADER 1366 depends on MIPS_VPE_LOADER
@@ -1496,7 +1506,7 @@ source "mm/Kconfig"
1496 1506
1497config SMP 1507config SMP
1498 bool "Multi-Processing support" 1508 bool "Multi-Processing support"
1499 depends on CPU_RM9000 || (SIBYTE_SB1250 && !SIBYTE_STANDALONE) || SGI_IP27 1509 depends on CPU_RM9000 || (SIBYTE_SB1250 && !SIBYTE_STANDALONE) || SGI_IP27 || MIPS_MT_SMP
1500 ---help--- 1510 ---help---
1501 This enables support for systems with more than one CPU. If you have 1511 This enables support for systems with more than one CPU. If you have
1502 a system with only one CPU, like most personal computers, say N. If 1512 a system with only one CPU, like most personal computers, say N. If
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 0f527063a8a8..4c09e1acafd7 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -34,6 +34,8 @@ obj-$(CONFIG_CPU_R6000) += r6000_fpu.o r4k_switch.o
34 34
35obj-$(CONFIG_SMP) += smp.o 35obj-$(CONFIG_SMP) += smp.o
36 36
37obj-$(CONFIG_MIPS_MT_SMP) += smp_mt.o
38
37obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o 39obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o
38obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o 40obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o
39 41
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
index fd904d1e4190..aa18a8b7b380 100644
--- a/arch/mips/kernel/genex.S
+++ b/arch/mips/kernel/genex.S
@@ -323,6 +323,7 @@ NESTED(nmi_handler, PT_SIZE, sp)
323 BUILD_HANDLER mdmx mdmx sti silent /* #22 */ 323 BUILD_HANDLER mdmx mdmx sti silent /* #22 */
324 BUILD_HANDLER watch watch sti verbose /* #23 */ 324 BUILD_HANDLER watch watch sti verbose /* #23 */
325 BUILD_HANDLER mcheck mcheck cli verbose /* #24 */ 325 BUILD_HANDLER mcheck mcheck cli verbose /* #24 */
326 BUILD_HANDLER mt mt sti verbose /* #25 */
326 BUILD_HANDLER dsp dsp sti silent /* #26 */ 327 BUILD_HANDLER dsp dsp sti silent /* #26 */
327 BUILD_HANDLER reserved reserved sti verbose /* others */ 328 BUILD_HANDLER reserved reserved sti verbose /* others */
328 329
diff --git a/arch/mips/kernel/smp_mt.c b/arch/mips/kernel/smp_mt.c
new file mode 100644
index 000000000000..d429544ba4bc
--- /dev/null
+++ b/arch/mips/kernel/smp_mt.c
@@ -0,0 +1,366 @@
1/*
2 * Copyright (C) 2004, 2005 MIPS Technologies, Inc. All rights reserved.
3 *
4 * Elizabeth Clarke (beth@mips.com)
5 *
6 * This program is free software; you can distribute it and/or modify it
7 * under the terms of the GNU General Public License (Version 2) as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
18 *
19 */
20#include <linux/kernel.h>
21#include <linux/sched.h>
22#include <linux/cpumask.h>
23#include <linux/interrupt.h>
24#include <linux/compiler.h>
25
26#include <asm/atomic.h>
27#include <asm/cpu.h>
28#include <asm/processor.h>
29#include <asm/system.h>
30#include <asm/hardirq.h>
31#include <asm/mmu_context.h>
32#include <asm/smp.h>
33#include <asm/time.h>
34#include <asm/mipsregs.h>
35#include <asm/mipsmtregs.h>
36#include <asm/cacheflush.h>
37#include <asm/mips-boards/maltaint.h>
38
39#define MIPS_CPU_IPI_RESCHED_IRQ 0
40#define MIPS_CPU_IPI_CALL_IRQ 1
41
42static int cpu_ipi_resched_irq, cpu_ipi_call_irq;
43
44#if 0
45static void dump_mtregisters(int vpe, int tc)
46{
47 printk("vpe %d tc %d\n", vpe, tc);
48
49 settc(tc);
50
51 printk(" c0 status 0x%lx\n", read_vpe_c0_status());
52 printk(" vpecontrol 0x%lx\n", read_vpe_c0_vpecontrol());
53 printk(" vpeconf0 0x%lx\n", read_vpe_c0_vpeconf0());
54 printk(" tcstatus 0x%lx\n", read_tc_c0_tcstatus());
55 printk(" tcrestart 0x%lx\n", read_tc_c0_tcrestart());
56 printk(" tcbind 0x%lx\n", read_tc_c0_tcbind());
57 printk(" tchalt 0x%lx\n", read_tc_c0_tchalt());
58}
59#endif
60
61void __init sanitize_tlb_entries(void)
62{
63 int i, tlbsiz;
64 unsigned long mvpconf0, ncpu;
65
66 if (!cpu_has_mipsmt)
67 return;
68
69 set_c0_mvpcontrol(MVPCONTROL_VPC);
70
71 /* Disable TLB sharing */
72 clear_c0_mvpcontrol(MVPCONTROL_STLB);
73
74 mvpconf0 = read_c0_mvpconf0();
75
76 printk(KERN_INFO "MVPConf0 0x%lx TLBS %lx PTLBE %ld\n", mvpconf0,
77 (mvpconf0 & MVPCONF0_TLBS) >> MVPCONF0_TLBS_SHIFT,
78 (mvpconf0 & MVPCONF0_PTLBE) >> MVPCONF0_PTLBE_SHIFT);
79
80 tlbsiz = (mvpconf0 & MVPCONF0_PTLBE) >> MVPCONF0_PTLBE_SHIFT;
81 ncpu = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
82
83 printk(" tlbsiz %d ncpu %ld\n", tlbsiz, ncpu);
84
85 if (tlbsiz > 0) {
86 /* share them out across the vpe's */
87 tlbsiz /= ncpu;
88
89 printk(KERN_INFO "setting Config1.MMU_size to %d\n", tlbsiz);
90
91 for (i = 0; i < ncpu; i++) {
92 settc(i);
93
94 if (i == 0)
95 write_c0_config1((read_c0_config1() & ~(0x3f << 25)) | (tlbsiz << 25));
96 else
97 write_vpe_c0_config1((read_vpe_c0_config1() & ~(0x3f << 25)) |
98 (tlbsiz << 25));
99 }
100 }
101
102 clear_c0_mvpcontrol(MVPCONTROL_VPC);
103}
104
105#if 0
106/*
107 * Use c0_MVPConf0 to find out how many CPUs are available, setting up
108 * phys_cpu_present_map and the logical/physical mappings.
109 */
110void __init prom_build_cpu_map(void)
111{
112 int i, num, ncpus;
113
114 cpus_clear(phys_cpu_present_map);
115
116 /* assume we boot on cpu 0.... */
117 cpu_set(0, phys_cpu_present_map);
118 __cpu_number_map[0] = 0;
119 __cpu_logical_map[0] = 0;
120
121 if (cpu_has_mipsmt) {
122 ncpus = ((read_c0_mvpconf0() & (MVPCONF0_PVPE)) >> MVPCONF0_PVPE_SHIFT) + 1;
123 for (i=1, num=0; i< NR_CPUS && i<ncpus; i++) {
124 cpu_set(i, phys_cpu_present_map);
125 __cpu_number_map[i] = ++num;
126 __cpu_logical_map[num] = i;
127 }
128
129 printk(KERN_INFO "%i available secondary CPU(s)\n", num);
130 }
131}
132#endif
133
134static void ipi_resched_dispatch (struct pt_regs *regs)
135{
136 do_IRQ(MIPS_CPU_IPI_RESCHED_IRQ, regs);
137}
138
139static void ipi_call_dispatch (struct pt_regs *regs)
140{
141 do_IRQ(MIPS_CPU_IPI_CALL_IRQ, regs);
142}
143
144irqreturn_t ipi_resched_interrupt(int irq, void *dev_id, struct pt_regs *regs)
145{
146 return IRQ_HANDLED;
147}
148
149irqreturn_t ipi_call_interrupt(int irq, void *dev_id, struct pt_regs *regs)
150{
151 smp_call_function_interrupt();
152
153 return IRQ_HANDLED;
154}
155
156static struct irqaction irq_resched = {
157 .handler = ipi_resched_interrupt,
158 .flags = SA_INTERRUPT,
159 .name = "IPI_resched"
160};
161
162static struct irqaction irq_call = {
163 .handler = ipi_call_interrupt,
164 .flags = SA_INTERRUPT,
165 .name = "IPI_call"
166};
167
168/*
169 * Common setup before any secondaries are started
170 * Make sure all CPU's are in a sensible state before we boot any of the
171 * secondarys
172 */
173void prom_prepare_cpus(unsigned int max_cpus)
174{
175 unsigned long val;
176 int i, num;
177
178 if (!cpu_has_mipsmt)
179 return;
180
181 /* disable MT so we can configure */
182 dvpe();
183 dmt();
184
185 /* Put MVPE's into 'configuration state' */
186 set_c0_mvpcontrol(MVPCONTROL_VPC);
187
188 val = read_c0_mvpconf0();
189
190 /* we'll always have more TC's than VPE's, so loop setting everything
191 to a sensible state */
192 for (i = 0, num = 0; i <= ((val & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT); i++) {
193 settc(i);
194
195 /* VPE's */
196 if (i <= ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)) {
197
198 /* deactivate all but vpe0 */
199 if (i != 0) {
200 unsigned long tmp = read_vpe_c0_vpeconf0();
201
202 tmp &= ~VPECONF0_VPA;
203
204 /* master VPE */
205 tmp |= VPECONF0_MVP;
206 write_vpe_c0_vpeconf0(tmp);
207
208 /* Record this as available CPU */
209 if (i < max_cpus) {
210 cpu_set(i, phys_cpu_present_map);
211 __cpu_number_map[i] = ++num;
212 __cpu_logical_map[num] = i;
213 }
214 }
215
216 /* disable multi-threading with TC's */
217 write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);
218
219 if (i != 0) {
220 write_vpe_c0_status((read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0);
221 write_vpe_c0_cause(read_vpe_c0_cause() & ~CAUSEF_IP);
222
223 /* set config to be the same as vpe0, particularly kseg0 coherency alg */
224 write_vpe_c0_config( read_c0_config());
225 }
226
227 }
228
229 /* TC's */
230
231 if (i != 0) {
232 unsigned long tmp;
233
234 /* bind a TC to each VPE, May as well put all excess TC's
235 on the last VPE */
236 if ( i >= (((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)+1) )
237 write_tc_c0_tcbind(read_tc_c0_tcbind() | ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) );
238 else {
239 write_tc_c0_tcbind( read_tc_c0_tcbind() | i);
240
241 /* and set XTC */
242 write_vpe_c0_vpeconf0( read_vpe_c0_vpeconf0() | (i << VPECONF0_XTC_SHIFT));
243 }
244
245 tmp = read_tc_c0_tcstatus();
246
247 /* mark not allocated and not dynamically allocatable */
248 tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
249 tmp |= TCSTATUS_IXMT; /* interrupt exempt */
250 write_tc_c0_tcstatus(tmp);
251
252 write_tc_c0_tchalt(TCHALT_H);
253 }
254 }
255
256 /* Release config state */
257 clear_c0_mvpcontrol(MVPCONTROL_VPC);
258
259 /* We'll wait until starting the secondaries before starting MVPE */
260
261 printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num);
262
263 /* set up ipi interrupts */
264 if (cpu_has_vint) {
265 set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch);
266 set_vi_handler (MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
267 }
268
269 cpu_ipi_resched_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
270 cpu_ipi_call_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ;
271
272 setup_irq(cpu_ipi_resched_irq, &irq_resched);
273 setup_irq(cpu_ipi_call_irq, &irq_call);
274
275 /* need to mark IPI's as IRQ_PER_CPU */
276 irq_desc[cpu_ipi_resched_irq].status |= IRQ_PER_CPU;
277 irq_desc[cpu_ipi_call_irq].status |= IRQ_PER_CPU;
278}
279
280/*
281 * Setup the PC, SP, and GP of a secondary processor and start it
282 * running!
283 * smp_bootstrap is the place to resume from
284 * __KSTK_TOS(idle) is apparently the stack pointer
285 * (unsigned long)idle->thread_info the gp
286 * assumes a 1:1 mapping of TC => VPE
287 */
288void prom_boot_secondary(int cpu, struct task_struct *idle)
289{
290 dvpe();
291 set_c0_mvpcontrol(MVPCONTROL_VPC);
292
293 settc(cpu);
294
295 /* restart */
296 write_tc_c0_tcrestart((unsigned long)&smp_bootstrap);
297
298 /* enable the tc this vpe/cpu will be running */
299 write_tc_c0_tcstatus((read_tc_c0_tcstatus() & ~TCSTATUS_IXMT) | TCSTATUS_A);
300
301 write_tc_c0_tchalt(0);
302
303 /* enable the VPE */
304 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
305
306 /* stack pointer */
307 write_tc_gpr_sp( __KSTK_TOS(idle));
308
309 /* global pointer */
310 write_tc_gpr_gp((unsigned long)idle->thread_info);
311
312 flush_icache_range((unsigned long)idle->thread_info,
313 (unsigned long)idle->thread_info +
314 sizeof(struct thread_info));
315
316 /* finally out of configuration and into chaos */
317 clear_c0_mvpcontrol(MVPCONTROL_VPC);
318
319 evpe(EVPE_ENABLE);
320}
321
322void prom_init_secondary(void)
323{
324 write_c0_status((read_c0_status() & ~ST0_IM ) |
325 (STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP7));
326}
327
328void prom_smp_finish(void)
329{
330 write_c0_compare(read_c0_count() + (8* mips_hpt_frequency/HZ));
331
332 local_irq_enable();
333}
334
335void prom_cpus_done(void)
336{
337}
338
339void core_send_ipi(int cpu, unsigned int action)
340{
341 int i;
342 unsigned long flags;
343 int vpflags;
344
345 local_irq_save (flags);
346
347 vpflags = dvpe(); /* cant access the other CPU's registers whilst MVPE enabled */
348
349 switch (action) {
350 case SMP_CALL_FUNCTION:
351 i = C_SW1;
352 break;
353
354 case SMP_RESCHEDULE_YOURSELF:
355 default:
356 i = C_SW0;
357 break;
358 }
359
360 /* 1:1 mapping of vpe and tc... */
361 settc(cpu);
362 write_vpe_c0_cause(read_vpe_c0_cause() | i);
363 evpe(vpflags);
364
365 local_irq_restore(flags);
366}
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 876aff71cd2e..e38f24b2b3db 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -28,6 +28,8 @@
28#include <asm/cpu.h> 28#include <asm/cpu.h>
29#include <asm/dsp.h> 29#include <asm/dsp.h>
30#include <asm/fpu.h> 30#include <asm/fpu.h>
31#include <asm/mipsregs.h>
32#include <asm/mipsmtregs.h>
31#include <asm/module.h> 33#include <asm/module.h>
32#include <asm/pgtable.h> 34#include <asm/pgtable.h>
33#include <asm/ptrace.h> 35#include <asm/ptrace.h>
@@ -56,6 +58,7 @@ extern asmlinkage void handle_tr(void);
56extern asmlinkage void handle_fpe(void); 58extern asmlinkage void handle_fpe(void);
57extern asmlinkage void handle_mdmx(void); 59extern asmlinkage void handle_mdmx(void);
58extern asmlinkage void handle_watch(void); 60extern asmlinkage void handle_watch(void);
61extern asmlinkage void handle_mt(void);
59extern asmlinkage void handle_dsp(void); 62extern asmlinkage void handle_dsp(void);
60extern asmlinkage void handle_mcheck(void); 63extern asmlinkage void handle_mcheck(void);
61extern asmlinkage void handle_reserved(void); 64extern asmlinkage void handle_reserved(void);
@@ -797,6 +800,14 @@ asmlinkage void do_mcheck(struct pt_regs *regs)
797 (regs->cp0_status & ST0_TS) ? "" : "not "); 800 (regs->cp0_status & ST0_TS) ? "" : "not ");
798} 801}
799 802
803asmlinkage void do_mt(struct pt_regs *regs)
804{
805 die_if_kernel("MIPS MT Thread exception in kernel", regs);
806
807 force_sig(SIGILL, current);
808}
809
810
800asmlinkage void do_dsp(struct pt_regs *regs) 811asmlinkage void do_dsp(struct pt_regs *regs)
801{ 812{
802 if (cpu_has_dsp) 813 if (cpu_has_dsp)
@@ -1338,6 +1349,9 @@ void __init trap_init(void)
1338 if (cpu_has_mcheck) 1349 if (cpu_has_mcheck)
1339 set_except_vector(24, handle_mcheck); 1350 set_except_vector(24, handle_mcheck);
1340 1351
1352 if (cpu_has_mipsmt)
1353 set_except_vector(25, handle_mt);
1354
1341 if (cpu_has_dsp) 1355 if (cpu_has_dsp)
1342 set_except_vector(26, handle_dsp); 1356 set_except_vector(26, handle_dsp);
1343 1357
diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c
index 6bf42ba08f09..97fefcc9dbe7 100644
--- a/arch/mips/kernel/vpe.c
+++ b/arch/mips/kernel/vpe.c
@@ -32,7 +32,7 @@
32 * mknod /dev/vpe0 c 63 0 32 * mknod /dev/vpe0 c 63 0
33 * mknod /dev/vpe1 c 63 1 33 * mknod /dev/vpe1 c 63 1
34 */ 34 */
35 35#include <linux/config.h>
36#include <linux/kernel.h> 36#include <linux/kernel.h>
37#include <linux/module.h> 37#include <linux/module.h>
38#include <linux/fs.h> 38#include <linux/fs.h>
@@ -49,6 +49,7 @@
49#include <linux/poll.h> 49#include <linux/poll.h>
50#include <linux/bootmem.h> 50#include <linux/bootmem.h>
51#include <asm/mipsregs.h> 51#include <asm/mipsregs.h>
52#include <asm/mipsmtregs.h>
52#include <asm/cacheflush.h> 53#include <asm/cacheflush.h>
53#include <asm/atomic.h> 54#include <asm/atomic.h>
54#include <asm/cpu.h> 55#include <asm/cpu.h>
@@ -697,7 +698,7 @@ int vpe_run(vpe_t * v)
697 dvpe(); 698 dvpe();
698 699
699 /* Put MVPE's into 'configuration state' */ 700 /* Put MVPE's into 'configuration state' */
700 write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_VPC); 701 set_c0_mvpcontrol(MVPCONTROL_VPC);
701 702
702 if (!list_empty(&v->tc)) { 703 if (!list_empty(&v->tc)) {
703 if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) { 704 if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
@@ -760,7 +761,7 @@ int vpe_run(vpe_t * v)
760 write_vpe_c0_cause(0); 761 write_vpe_c0_cause(0);
761 762
762 /* take system out of configuration state */ 763 /* take system out of configuration state */
763 write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_VPC); 764 clear_c0_mvpcontrol(MVPCONTROL_VPC);
764 765
765 /* clear interrupts enabled IE, ERL, EXL, and KSU from c0 status */ 766 /* clear interrupts enabled IE, ERL, EXL, and KSU from c0 status */
766 write_vpe_c0_status(read_vpe_c0_status() & ~(ST0_ERL | ST0_KSU | ST0_IE | ST0_EXL)); 767 write_vpe_c0_status(read_vpe_c0_status() & ~(ST0_ERL | ST0_KSU | ST0_IE | ST0_EXL));
@@ -1134,7 +1135,7 @@ int vpe_free(vpe_handle vpe)
1134 evpe_flags = dvpe(); 1135 evpe_flags = dvpe();
1135 1136
1136 /* Put MVPE's into 'configuration state' */ 1137 /* Put MVPE's into 'configuration state' */
1137 write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_VPC); 1138 set_c0_mvpcontrol(MVPCONTROL_VPC);
1138 1139
1139 settc(t->index); 1140 settc(t->index);
1140 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA); 1141 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
@@ -1145,7 +1146,7 @@ int vpe_free(vpe_handle vpe)
1145 1146
1146 v->state = VPE_STATE_UNUSED; 1147 v->state = VPE_STATE_UNUSED;
1147 1148
1148 write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_VPC); 1149 clear_c0_mvpcontrol(MVPCONTROL_VPC);
1149 evpe(evpe_flags); 1150 evpe(evpe_flags);
1150 1151
1151 return 0; 1152 return 0;
@@ -1191,7 +1192,7 @@ static int __init vpe_module_init(void)
1191 dvpe(); 1192 dvpe();
1192 1193
1193 /* Put MVPE's into 'configuration state' */ 1194 /* Put MVPE's into 'configuration state' */
1194 write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_VPC); 1195 set_c0_mvpcontrol(MVPCONTROL_VPC);
1195 1196
1196 /* dump_mtregs(); */ 1197 /* dump_mtregs(); */
1197 1198
@@ -1270,7 +1271,7 @@ static int __init vpe_module_init(void)
1270 } 1271 }
1271 1272
1272 /* release config state */ 1273 /* release config state */
1273 write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_VPC); 1274 clear_c0_mvpcontrol(MVPCONTROL_VPC);
1274 1275
1275 return 0; 1276 return 0;
1276} 1277}
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c
index 3a6f1428b2cb..72a12d931cba 100644
--- a/arch/mips/mips-boards/generic/time.c
+++ b/arch/mips/mips-boards/generic/time.c
@@ -61,6 +61,15 @@ static unsigned int display_count = 0;
61static unsigned int timer_tick_count=0; 61static unsigned int timer_tick_count=0;
62static int mips_cpu_timer_irq; 62static int mips_cpu_timer_irq;
63 63
64static inline void scroll_display_message(void)
65{
66 if ((timer_tick_count++ % HZ) == 0) {
67 mips_display_message(&display_string[display_count++]);
68 if (display_count == MAX_DISPLAY_COUNT)
69 display_count = 0;
70 }
71}
72
64static void mips_timer_dispatch (struct pt_regs *regs) 73static void mips_timer_dispatch (struct pt_regs *regs)
65{ 74{
66 do_IRQ (mips_cpu_timer_irq, regs); 75 do_IRQ (mips_cpu_timer_irq, regs);
@@ -68,17 +77,42 @@ static void mips_timer_dispatch (struct pt_regs *regs)
68 77
69irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 78irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
70{ 79{
80#ifdef CONFIG_SMP
81 int cpu = smp_processor_id();
82
83 if (cpu == 0) {
84 /*
85 * CPU 0 handles the global timer interrupt job and process accounting
86 * resets count/compare registers to trigger next timer int.
87 */
88 (void) timer_interrupt(irq, dev_id, regs);
89 scroll_display_message();
90 }
91 else {
92 /* Everyone else needs to reset the timer int here as
93 ll_local_timer_interrupt doesn't */
94 /*
95 * FIXME: need to cope with counter underflow.
96 * More support needs to be added to kernel/time for
97 * counter/timer interrupts on multiple CPU's
98 */
99 write_c0_compare (read_c0_count() + (mips_hpt_frequency/HZ));
100 /*
101 * other CPUs should do profiling and process accounting
102 */
103 local_timer_interrupt (irq, dev_id, regs);
104 }
105
106 return IRQ_HANDLED;
107#else
71 irqreturn_t r; 108 irqreturn_t r;
72 109
73 r = timer_interrupt(irq, dev_id, regs); 110 r = timer_interrupt(irq, dev_id, regs);
74 111
75 if ((timer_tick_count++ % HZ) == 0) { 112 scroll_display_message();
76 mips_display_message(&display_string[display_count++]);
77 if (display_count == MAX_DISPLAY_COUNT)
78 display_count = 0;
79 }
80 113
81 return r; 114 return r;
115#endif
82} 116}
83 117
84/* 118/*
@@ -176,6 +210,13 @@ void __init mips_timer_setup(struct irqaction *irq)
176 irq->handler = mips_timer_interrupt; /* we use our own handler */ 210 irq->handler = mips_timer_interrupt; /* we use our own handler */
177 setup_irq(mips_cpu_timer_irq, irq); 211 setup_irq(mips_cpu_timer_irq, irq);
178 212
213#ifdef CONFIG_SMP
214 /* irq_desc(riptor) is a global resource, when the interrupt overlaps
215 on seperate cpu's the first one tries to handle the second interrupt.
216 The effect is that the int remains disabled on the second cpu.
217 Mark the interrupt with IRQ_PER_CPU to avoid any confusion */
218 irq_desc[mips_cpu_timer_irq].status |= IRQ_PER_CPU;
219#endif
179 220
180 /* to generate the first timer interrupt */ 221 /* to generate the first timer interrupt */
181 write_c0_compare (read_c0_count() + mips_hpt_frequency/HZ); 222 write_c0_compare (read_c0_count() + mips_hpt_frequency/HZ);