aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/Kconfig18
-rw-r--r--arch/mips/kernel/Makefile3
-rw-r--r--arch/mips/kernel/cpu-probe.c5
-rw-r--r--arch/mips/kernel/irq-gic.c295
-rw-r--r--arch/mips/kernel/smp-cmp.c265
-rw-r--r--arch/mips/kernel/smp-mt.c96
-rw-r--r--arch/mips/kernel/smp.c4
-rw-r--r--arch/mips/kernel/smtc.c3
-rw-r--r--arch/mips/kernel/sync-r4k.c159
-rw-r--r--arch/mips/kernel/traps.c111
-rw-r--r--arch/mips/mips-boards/generic/Makefile1
-rw-r--r--arch/mips/mips-boards/generic/amon.c80
-rw-r--r--arch/mips/mips-boards/generic/init.c3
-rw-r--r--arch/mips/mips-boards/generic/time.c29
-rw-r--r--arch/mips/mips-boards/malta/Makefile1
-rw-r--r--arch/mips/mips-boards/malta/malta_int.c346
-rw-r--r--arch/mips/mips-boards/malta/malta_setup.c6
-rw-r--r--arch/mips/mm/c-r4k.c43
-rw-r--r--arch/mips/mm/init.c2
-rw-r--r--arch/mips/oprofile/common.c1
-rw-r--r--arch/mips/oprofile/op_model_mipsxx.c34
21 files changed, 1389 insertions, 116 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 8724ed3298d3..89b03775a195 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -221,6 +221,7 @@ config MIPS_MALTA
221 select DMA_NONCOHERENT 221 select DMA_NONCOHERENT
222 select GENERIC_ISA_DMA 222 select GENERIC_ISA_DMA
223 select IRQ_CPU 223 select IRQ_CPU
224 select IRQ_GIC
224 select HW_HAS_PCI 225 select HW_HAS_PCI
225 select I8253 226 select I8253
226 select I8259 227 select I8259
@@ -840,6 +841,9 @@ config MIPS_NILE4
840config MIPS_DISABLE_OBSOLETE_IDE 841config MIPS_DISABLE_OBSOLETE_IDE
841 bool 842 bool
842 843
844config SYNC_R4K
845 bool
846
843config NO_IOPORT 847config NO_IOPORT
844 def_bool n 848 def_bool n
845 849
@@ -909,6 +913,9 @@ config IRQ_TXX9
909config IRQ_GT641XX 913config IRQ_GT641XX
910 bool 914 bool
911 915
916config IRQ_GIC
917 bool
918
912config MIPS_BOARDS_GEN 919config MIPS_BOARDS_GEN
913 bool 920 bool
914 921
@@ -1811,6 +1818,17 @@ config NR_CPUS
1811 performance should round up your number of processors to the next 1818 performance should round up your number of processors to the next
1812 power of two. 1819 power of two.
1813 1820
1821config MIPS_CMP
1822 bool "MIPS CMP framework support"
1823 depends on SMP
1824 select SYNC_R4K
1825 select SYS_SUPPORTS_SCHED_SMT
1826 select WEAK_ORDERING
1827 default n
1828 help
1829 This is a placeholder option for the GCMP work. It will need to
1830 be handled differently...
1831
1814source "kernel/time/Kconfig" 1832source "kernel/time/Kconfig"
1815 1833
1816# 1834#
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 67d97fb02c38..d0ca4d41bb74 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_CEVT_TXX9) += cevt-txx9.o
16obj-$(CONFIG_CSRC_BCM1480) += csrc-bcm1480.o 16obj-$(CONFIG_CSRC_BCM1480) += csrc-bcm1480.o
17obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o 17obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o
18obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o 18obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o
19obj-$(CONFIG_SYNC_R4K) += sync-r4k.o
19 20
20binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \ 21binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \
21 irix5sys.o sysirix.o 22 irix5sys.o sysirix.o
@@ -50,6 +51,7 @@ obj-$(CONFIG_MIPS_MT) += mips-mt.o
50obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o 51obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o
51obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o 52obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o
52obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o 53obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o
54obj-$(CONFIG_MIPS_CMP) += smp-cmp.o
53obj-$(CONFIG_CPU_MIPSR2) += spram.o 55obj-$(CONFIG_CPU_MIPSR2) += spram.o
54 56
55obj-$(CONFIG_MIPS_APSP_KSPD) += kspd.o 57obj-$(CONFIG_MIPS_APSP_KSPD) += kspd.o
@@ -63,6 +65,7 @@ obj-$(CONFIG_IRQ_CPU_RM9K) += irq-rm9000.o
63obj-$(CONFIG_MIPS_BOARDS_GEN) += irq-msc01.o 65obj-$(CONFIG_MIPS_BOARDS_GEN) += irq-msc01.o
64obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o 66obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o
65obj-$(CONFIG_IRQ_GT641XX) += irq-gt641xx.o 67obj-$(CONFIG_IRQ_GT641XX) += irq-gt641xx.o
68obj-$(CONFIG_IRQ_GIC) += irq-gic.o
66 69
67obj-$(CONFIG_32BIT) += scall32-o32.o 70obj-$(CONFIG_32BIT) += scall32-o32.o
68obj-$(CONFIG_64BIT) += scall64-64.o 71obj-$(CONFIG_64BIT) += scall64-64.o
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index add717dccf77..a742a967169a 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -169,6 +169,7 @@ static inline void check_wait(void)
169 169
170 case CPU_24K: 170 case CPU_24K:
171 case CPU_34K: 171 case CPU_34K:
172 case CPU_1004K:
172 cpu_wait = r4k_wait; 173 cpu_wait = r4k_wait;
173 if (read_c0_config7() & MIPS_CONF7_WII) 174 if (read_c0_config7() & MIPS_CONF7_WII)
174 cpu_wait = r4k_wait_irqoff; 175 cpu_wait = r4k_wait_irqoff;
@@ -717,6 +718,9 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c)
717 case PRID_IMP_74K: 718 case PRID_IMP_74K:
718 c->cputype = CPU_74K; 719 c->cputype = CPU_74K;
719 break; 720 break;
721 case PRID_IMP_1004K:
722 c->cputype = CPU_1004K;
723 break;
720 } 724 }
721 725
722 spram_config(); 726 spram_config();
@@ -884,6 +888,7 @@ static __cpuinit const char *cpu_to_name(struct cpuinfo_mips *c)
884 case CPU_24K: name = "MIPS 24K"; break; 888 case CPU_24K: name = "MIPS 24K"; break;
885 case CPU_25KF: name = "MIPS 25Kf"; break; 889 case CPU_25KF: name = "MIPS 25Kf"; break;
886 case CPU_34K: name = "MIPS 34K"; break; 890 case CPU_34K: name = "MIPS 34K"; break;
891 case CPU_1004K: name = "MIPS 1004K"; break;
887 case CPU_74K: name = "MIPS 74K"; break; 892 case CPU_74K: name = "MIPS 74K"; break;
888 case CPU_VR4111: name = "NEC VR4111"; break; 893 case CPU_VR4111: name = "NEC VR4111"; break;
889 case CPU_VR4121: name = "NEC VR4121"; break; 894 case CPU_VR4121: name = "NEC VR4121"; break;
diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c
new file mode 100644
index 000000000000..f0a4bb19e096
--- /dev/null
+++ b/arch/mips/kernel/irq-gic.c
@@ -0,0 +1,295 @@
1#undef DEBUG
2
3#include <linux/bitmap.h>
4#include <linux/init.h>
5
6#include <asm/io.h>
7#include <asm/gic.h>
8#include <asm/gcmpregs.h>
9#include <asm/mips-boards/maltaint.h>
10#include <asm/irq.h>
11#include <linux/hardirq.h>
12#include <asm-generic/bitops/find.h>
13
14
15static unsigned long _gic_base;
16static unsigned int _irqbase, _mapsize, numvpes, numintrs;
17static struct gic_intr_map *_intrmap;
18
19static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
20static struct gic_pending_regs pending_regs[NR_CPUS];
21static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
22
23#define gic_wedgeb2bok 0 /*
24 * Can GIC handle b2b writes to wedge register?
25 */
26#if gic_wedgeb2bok == 0
27static DEFINE_SPINLOCK(gic_wedgeb2b_lock);
28#endif
29
30void gic_send_ipi(unsigned int intr)
31{
32#if gic_wedgeb2bok == 0
33 unsigned long flags;
34#endif
35 pr_debug("CPU%d: %s status %08x\n", smp_processor_id(), __func__,
36 read_c0_status());
37 if (!gic_wedgeb2bok)
38 spin_lock_irqsave(&gic_wedgeb2b_lock, flags);
39 GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr);
40 if (!gic_wedgeb2bok) {
41 (void) GIC_REG(SHARED, GIC_SH_CONFIG);
42 spin_unlock_irqrestore(&gic_wedgeb2b_lock, flags);
43 }
44}
45
46/* This is Malta specific and needs to be exported */
47static void vpe_local_setup(unsigned int numvpes)
48{
49 int i;
50 unsigned long timer_interrupt = 5, perf_interrupt = 5;
51 unsigned int vpe_ctl;
52
53 /*
54 * Setup the default performance counter timer interrupts
55 * for all VPEs
56 */
57 for (i = 0; i < numvpes; i++) {
58 GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i);
59
60 /* Are Interrupts locally routable? */
61 GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl);
62 if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK)
63 GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP),
64 GIC_MAP_TO_PIN_MSK | timer_interrupt);
65
66 if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK)
67 GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP),
68 GIC_MAP_TO_PIN_MSK | perf_interrupt);
69 }
70}
71
72unsigned int gic_get_int(void)
73{
74 unsigned int i;
75 unsigned long *pending, *intrmask, *pcpu_mask;
76 unsigned long *pending_abs, *intrmask_abs;
77
78 /* Get per-cpu bitmaps */
79 pending = pending_regs[smp_processor_id()].pending;
80 intrmask = intrmask_regs[smp_processor_id()].intrmask;
81 pcpu_mask = pcpu_masks[smp_processor_id()].pcpu_mask;
82
83 pending_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED,
84 GIC_SH_PEND_31_0_OFS);
85 intrmask_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED,
86 GIC_SH_MASK_31_0_OFS);
87
88 for (i = 0; i < BITS_TO_LONGS(GIC_NUM_INTRS); i++) {
89 GICREAD(*pending_abs, pending[i]);
90 GICREAD(*intrmask_abs, intrmask[i]);
91 pending_abs++;
92 intrmask_abs++;
93 }
94
95 bitmap_and(pending, pending, intrmask, GIC_NUM_INTRS);
96 bitmap_and(pending, pending, pcpu_mask, GIC_NUM_INTRS);
97
98 i = find_first_bit(pending, GIC_NUM_INTRS);
99
100 pr_debug("CPU%d: %s pend=%d\n", smp_processor_id(), __func__, i);
101
102 return i;
103}
104
105static unsigned int gic_irq_startup(unsigned int irq)
106{
107 pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
108 irq -= _irqbase;
109 /* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */
110 GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_SMASK_31_0_OFS + (irq / 32))),
111 1 << (irq % 32));
112 return 0;
113}
114
115static void gic_irq_ack(unsigned int irq)
116{
117#if gic_wedgeb2bok == 0
118 unsigned long flags;
119#endif
120 pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
121 irq -= _irqbase;
122 GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_RMASK_31_0_OFS + (irq / 32))),
123 1 << (irq % 32));
124
125 if (_intrmap[irq].trigtype == GIC_TRIG_EDGE) {
126 if (!gic_wedgeb2bok)
127 spin_lock_irqsave(&gic_wedgeb2b_lock, flags);
128 GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
129 if (!gic_wedgeb2bok) {
130 (void) GIC_REG(SHARED, GIC_SH_CONFIG);
131 spin_unlock_irqrestore(&gic_wedgeb2b_lock, flags);
132 }
133 }
134}
135
136static void gic_mask_irq(unsigned int irq)
137{
138 pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
139 irq -= _irqbase;
140 /* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */
141 GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_RMASK_31_0_OFS + (irq / 32))),
142 1 << (irq % 32));
143}
144
145static void gic_unmask_irq(unsigned int irq)
146{
147 pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
148 irq -= _irqbase;
149 /* FIXME: this is wrong for !GICISWORDLITTLEENDIAN */
150 GICWRITE(GIC_REG_ADDR(SHARED, (GIC_SH_SMASK_31_0_OFS + (irq / 32))),
151 1 << (irq % 32));
152}
153
154#ifdef CONFIG_SMP
155
156static DEFINE_SPINLOCK(gic_lock);
157
158static void gic_set_affinity(unsigned int irq, cpumask_t cpumask)
159{
160 cpumask_t tmp = CPU_MASK_NONE;
161 unsigned long flags;
162 int i;
163
164 pr_debug(KERN_DEBUG "%s called\n", __func__);
165 irq -= _irqbase;
166
167 cpus_and(tmp, cpumask, cpu_online_map);
168 if (cpus_empty(tmp))
169 return;
170
171 /* Assumption : cpumask refers to a single CPU */
172 spin_lock_irqsave(&gic_lock, flags);
173 for (;;) {
174 /* Re-route this IRQ */
175 GIC_SH_MAP_TO_VPE_SMASK(irq, first_cpu(tmp));
176
177 /*
178 * FIXME: assumption that _intrmap is ordered and has no holes
179 */
180
181 /* Update the intr_map */
182 _intrmap[irq].cpunum = first_cpu(tmp);
183
184 /* Update the pcpu_masks */
185 for (i = 0; i < NR_CPUS; i++)
186 clear_bit(irq, pcpu_masks[i].pcpu_mask);
187 set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask);
188
189 }
190 irq_desc[irq].affinity = cpumask;
191 spin_unlock_irqrestore(&gic_lock, flags);
192
193}
194#endif
195
196static struct irq_chip gic_irq_controller = {
197 .name = "MIPS GIC",
198 .startup = gic_irq_startup,
199 .ack = gic_irq_ack,
200 .mask = gic_mask_irq,
201 .mask_ack = gic_mask_irq,
202 .unmask = gic_unmask_irq,
203 .eoi = gic_unmask_irq,
204#ifdef CONFIG_SMP
205 .set_affinity = gic_set_affinity,
206#endif
207};
208
209static void __init setup_intr(unsigned int intr, unsigned int cpu,
210 unsigned int pin, unsigned int polarity, unsigned int trigtype)
211{
212 /* Setup Intr to Pin mapping */
213 if (pin & GIC_MAP_TO_NMI_MSK) {
214 GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), pin);
215 /* FIXME: hack to route NMI to all cpu's */
216 for (cpu = 0; cpu < NR_CPUS; cpu += 32) {
217 GICWRITE(GIC_REG_ADDR(SHARED,
218 GIC_SH_MAP_TO_VPE_REG_OFF(intr, cpu)),
219 0xffffffff);
220 }
221 } else {
222 GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)),
223 GIC_MAP_TO_PIN_MSK | pin);
224 /* Setup Intr to CPU mapping */
225 GIC_SH_MAP_TO_VPE_SMASK(intr, cpu);
226 }
227
228 /* Setup Intr Polarity */
229 GIC_SET_POLARITY(intr, polarity);
230
231 /* Setup Intr Trigger Type */
232 GIC_SET_TRIGGER(intr, trigtype);
233
234 /* Init Intr Masks */
235 GIC_SET_INTR_MASK(intr, 0);
236}
237
238static void __init gic_basic_init(void)
239{
240 unsigned int i, cpu;
241
242 /* Setup defaults */
243 for (i = 0; i < GIC_NUM_INTRS; i++) {
244 GIC_SET_POLARITY(i, GIC_POL_POS);
245 GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL);
246 GIC_SET_INTR_MASK(i, 0);
247 }
248
249 /* Setup specifics */
250 for (i = 0; i < _mapsize; i++) {
251 cpu = _intrmap[i].cpunum;
252 if (cpu == X)
253 continue;
254
255 setup_intr(_intrmap[i].intrnum,
256 _intrmap[i].cpunum,
257 _intrmap[i].pin,
258 _intrmap[i].polarity,
259 _intrmap[i].trigtype);
260 /* Initialise per-cpu Interrupt software masks */
261 if (_intrmap[i].ipiflag)
262 set_bit(_intrmap[i].intrnum, pcpu_masks[cpu].pcpu_mask);
263 }
264
265 vpe_local_setup(numvpes);
266
267 for (i = _irqbase; i < (_irqbase + numintrs); i++)
268 set_irq_chip(i, &gic_irq_controller);
269}
270
271void __init gic_init(unsigned long gic_base_addr,
272 unsigned long gic_addrspace_size,
273 struct gic_intr_map *intr_map, unsigned int intr_map_size,
274 unsigned int irqbase)
275{
276 unsigned int gicconfig;
277
278 _gic_base = (unsigned long) ioremap_nocache(gic_base_addr,
279 gic_addrspace_size);
280 _irqbase = irqbase;
281 _intrmap = intr_map;
282 _mapsize = intr_map_size;
283
284 GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig);
285 numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >>
286 GIC_SH_CONFIG_NUMINTRS_SHF;
287 numintrs = ((numintrs + 1) * 8);
288
289 numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >>
290 GIC_SH_CONFIG_NUMVPES_SHF;
291
292 pr_debug("%s called\n", __func__);
293
294 gic_basic_init();
295}
diff --git a/arch/mips/kernel/smp-cmp.c b/arch/mips/kernel/smp-cmp.c
new file mode 100644
index 000000000000..ca476c4f62a5
--- /dev/null
+++ b/arch/mips/kernel/smp-cmp.c
@@ -0,0 +1,265 @@
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.
5 *
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.
10 *
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.
14 *
15 * Copyright (C) 2007 MIPS Technologies, Inc.
16 * Chris Dearman (chris@mips.com)
17 */
18
19#undef DEBUG
20
21#include <linux/kernel.h>
22#include <linux/sched.h>
23#include <linux/cpumask.h>
24#include <linux/interrupt.h>
25#include <linux/compiler.h>
26
27#include <asm/atomic.h>
28#include <asm/cacheflush.h>
29#include <asm/cpu.h>
30#include <asm/processor.h>
31#include <asm/system.h>
32#include <asm/hardirq.h>
33#include <asm/mmu_context.h>
34#include <asm/smp.h>
35#include <asm/time.h>
36#include <asm/mipsregs.h>
37#include <asm/mipsmtregs.h>
38#include <asm/mips_mt.h>
39
40/*
41 * Crude manipulation of the CPU masks to control which
42 * which CPU's are brought online during initialisation
43 *
44 * Beware... this needs to be called after CPU discovery
45 * but before CPU bringup
46 */
47static int __init allowcpus(char *str)
48{
49 cpumask_t cpu_allow_map;
50 char buf[256];
51 int len;
52
53 cpus_clear(cpu_allow_map);
54 if (cpulist_parse(str, cpu_allow_map) == 0) {
55 cpu_set(0, cpu_allow_map);
56 cpus_and(cpu_possible_map, cpu_possible_map, cpu_allow_map);
57 len = cpulist_scnprintf(buf, sizeof(buf)-1, cpu_possible_map);
58 buf[len] = '\0';
59 pr_debug("Allowable CPUs: %s\n", buf);
60 return 1;
61 } else
62 return 0;
63}
64__setup("allowcpus=", allowcpus);
65
66static void ipi_call_function(unsigned int cpu)
67{
68 unsigned int action = 0;
69
70 pr_debug("CPU%d: %s cpu %d status %08x\n",
71 smp_processor_id(), __func__, cpu, read_c0_status());
72
73 switch (cpu) {
74 case 0:
75 action = GIC_IPI_EXT_INTR_CALLFNC_VPE0;
76 break;
77 case 1:
78 action = GIC_IPI_EXT_INTR_CALLFNC_VPE1;
79 break;
80 case 2:
81 action = GIC_IPI_EXT_INTR_CALLFNC_VPE2;
82 break;
83 case 3:
84 action = GIC_IPI_EXT_INTR_CALLFNC_VPE3;
85 break;
86 }
87 gic_send_ipi(action);
88}
89
90
91static void ipi_resched(unsigned int cpu)
92{
93 unsigned int action = 0;
94
95 pr_debug("CPU%d: %s cpu %d status %08x\n",
96 smp_processor_id(), __func__, cpu, read_c0_status());
97
98 switch (cpu) {
99 case 0:
100 action = GIC_IPI_EXT_INTR_RESCHED_VPE0;
101 break;
102 case 1:
103 action = GIC_IPI_EXT_INTR_RESCHED_VPE1;
104 break;
105 case 2:
106 action = GIC_IPI_EXT_INTR_RESCHED_VPE2;
107 break;
108 case 3:
109 action = GIC_IPI_EXT_INTR_RESCHED_VPE3;
110 break;
111 }
112 gic_send_ipi(action);
113}
114
115/*
116 * FIXME: This isn't restricted to CMP
117 * The SMVP kernel could use GIC interrupts if available
118 */
119void cmp_send_ipi_single(int cpu, unsigned int action)
120{
121 unsigned long flags;
122
123 local_irq_save(flags);
124
125 switch (action) {
126 case SMP_CALL_FUNCTION:
127 ipi_call_function(cpu);
128 break;
129
130 case SMP_RESCHEDULE_YOURSELF:
131 ipi_resched(cpu);
132 break;
133 }
134
135 local_irq_restore(flags);
136}
137
138static void cmp_send_ipi_mask(cpumask_t mask, unsigned int action)
139{
140 unsigned int i;
141
142 for_each_cpu_mask(i, mask)
143 cmp_send_ipi_single(i, action);
144}
145
146static void cmp_init_secondary(void)
147{
148 struct cpuinfo_mips *c = &current_cpu_data;
149
150 /* Assume GIC is present */
151 change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP6 |
152 STATUSF_IP7);
153
154 /* Enable per-cpu interrupts: platform specific */
155
156 c->core = (read_c0_ebase() >> 1) & 0xff;
157#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC)
158 c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE;
159#endif
160#ifdef CONFIG_MIPS_MT_SMTC
161 c->tc_id = (read_c0_tcbind() >> TCBIND_CURTC_SHIFT) & TCBIND_CURTC;
162#endif
163}
164
165static void cmp_smp_finish(void)
166{
167 pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__);
168
169 /* CDFIXME: remove this? */
170 write_c0_compare(read_c0_count() + (8 * mips_hpt_frequency / HZ));
171
172#ifdef CONFIG_MIPS_MT_FPAFF
173 /* If we have an FPU, enroll ourselves in the FPU-full mask */
174 if (cpu_has_fpu)
175 cpu_set(smp_processor_id(), mt_fpu_cpumask);
176#endif /* CONFIG_MIPS_MT_FPAFF */
177
178 local_irq_enable();
179}
180
181static void cmp_cpus_done(void)
182{
183 pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__);
184}
185
186/*
187 * Setup the PC, SP, and GP of a secondary processor and start it running
188 * smp_bootstrap is the place to resume from
189 * __KSTK_TOS(idle) is apparently the stack pointer
190 * (unsigned long)idle->thread_info the gp
191 */
192static void cmp_boot_secondary(int cpu, struct task_struct *idle)
193{
194 struct thread_info *gp = task_thread_info(idle);
195 unsigned long sp = __KSTK_TOS(idle);
196 unsigned long pc = (unsigned long)&smp_bootstrap;
197 unsigned long a0 = 0;
198
199 pr_debug("SMPCMP: CPU%d: %s cpu %d\n", smp_processor_id(),
200 __func__, cpu);
201
202#if 0
203 /* Needed? */
204 flush_icache_range((unsigned long)gp,
205 (unsigned long)(gp + sizeof(struct thread_info)));
206#endif
207
208 amon_cpu_start(cpu, pc, sp, gp, a0);
209}
210
211/*
212 * Common setup before any secondaries are started
213 */
214void __init cmp_smp_setup(void)
215{
216 int i;
217 int ncpu = 0;
218
219 pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__);
220
221#ifdef CONFIG_MIPS_MT_FPAFF
222 /* If we have an FPU, enroll ourselves in the FPU-full mask */
223 if (cpu_has_fpu)
224 cpu_set(0, mt_fpu_cpumask);
225#endif /* CONFIG_MIPS_MT_FPAFF */
226
227 for (i = 1; i < NR_CPUS; i++) {
228 if (amon_cpu_avail(i)) {
229 cpu_set(i, phys_cpu_present_map);
230 __cpu_number_map[i] = ++ncpu;
231 __cpu_logical_map[ncpu] = i;
232 }
233 }
234
235 if (cpu_has_mipsmt) {
236 unsigned int nvpe, mvpconf0 = read_c0_mvpconf0();
237
238 nvpe = ((mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1;
239 smp_num_siblings = nvpe;
240 }
241 pr_info("Detected %i available secondary CPU(s)\n", ncpu);
242}
243
244void __init cmp_prepare_cpus(unsigned int max_cpus)
245{
246 pr_debug("SMPCMP: CPU%d: %s max_cpus=%d\n",
247 smp_processor_id(), __func__, max_cpus);
248
249 /*
250 * FIXME: some of these options are per-system, some per-core and
251 * some per-cpu
252 */
253 mips_mt_set_cpuoptions();
254}
255
256struct plat_smp_ops cmp_smp_ops = {
257 .send_ipi_single = cmp_send_ipi_single,
258 .send_ipi_mask = cmp_send_ipi_mask,
259 .init_secondary = cmp_init_secondary,
260 .smp_finish = cmp_smp_finish,
261 .cpus_done = cmp_cpus_done,
262 .boot_secondary = cmp_boot_secondary,
263 .smp_setup = cmp_smp_setup,
264 .prepare_cpus = cmp_prepare_cpus,
265};
diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c
index e9c393a41775..87a1816c1f45 100644
--- a/arch/mips/kernel/smp-mt.c
+++ b/arch/mips/kernel/smp-mt.c
@@ -36,63 +36,7 @@
36#include <asm/mipsmtregs.h> 36#include <asm/mipsmtregs.h>
37#include <asm/mips_mt.h> 37#include <asm/mips_mt.h>
38 38
39#define MIPS_CPU_IPI_RESCHED_IRQ 0 39static void __init smvp_copy_vpe_config(void)
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
61static void ipi_resched_dispatch(void)
62{
63 do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ);
64}
65
66static void ipi_call_dispatch(void)
67{
68 do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ);
69}
70
71static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
72{
73 return IRQ_HANDLED;
74}
75
76static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
77{
78 smp_call_function_interrupt();
79
80 return IRQ_HANDLED;
81}
82
83static struct irqaction irq_resched = {
84 .handler = ipi_resched_interrupt,
85 .flags = IRQF_DISABLED|IRQF_PERCPU,
86 .name = "IPI_resched"
87};
88
89static struct irqaction irq_call = {
90 .handler = ipi_call_interrupt,
91 .flags = IRQF_DISABLED|IRQF_PERCPU,
92 .name = "IPI_call"
93};
94
95static void __init smp_copy_vpe_config(void)
96{ 40{
97 write_vpe_c0_status( 41 write_vpe_c0_status(
98 (read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0); 42 (read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0);
@@ -109,7 +53,7 @@ static void __init smp_copy_vpe_config(void)
109 write_vpe_c0_count(read_c0_count()); 53 write_vpe_c0_count(read_c0_count());
110} 54}
111 55
112static unsigned int __init smp_vpe_init(unsigned int tc, unsigned int mvpconf0, 56static unsigned int __init smvp_vpe_init(unsigned int tc, unsigned int mvpconf0,
113 unsigned int ncpu) 57 unsigned int ncpu)
114{ 58{
115 if (tc > ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)) 59 if (tc > ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT))
@@ -135,12 +79,12 @@ static unsigned int __init smp_vpe_init(unsigned int tc, unsigned int mvpconf0,
135 write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); 79 write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);
136 80
137 if (tc != 0) 81 if (tc != 0)
138 smp_copy_vpe_config(); 82 smvp_copy_vpe_config();
139 83
140 return ncpu; 84 return ncpu;
141} 85}
142 86
143static void __init smp_tc_init(unsigned int tc, unsigned int mvpconf0) 87static void __init smvp_tc_init(unsigned int tc, unsigned int mvpconf0)
144{ 88{
145 unsigned long tmp; 89 unsigned long tmp;
146 90
@@ -207,15 +151,20 @@ static void vsmp_send_ipi_mask(cpumask_t mask, unsigned int action)
207 151
208static void __cpuinit vsmp_init_secondary(void) 152static void __cpuinit vsmp_init_secondary(void)
209{ 153{
210 /* Enable per-cpu interrupts */ 154 extern int gic_present;
211 155
212 /* This is Malta specific: IPI,performance and timer inetrrupts */ 156 /* This is Malta specific: IPI,performance and timer inetrrupts */
213 write_c0_status((read_c0_status() & ~ST0_IM ) | 157 if (gic_present)
214 (STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP6 | STATUSF_IP7)); 158 change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 |
159 STATUSF_IP6 | STATUSF_IP7);
160 else
161 change_c0_status(ST0_IM, STATUSF_IP0 | STATUSF_IP1 |
162 STATUSF_IP6 | STATUSF_IP7);
215} 163}
216 164
217static void __cpuinit vsmp_smp_finish(void) 165static void __cpuinit vsmp_smp_finish(void)
218{ 166{
167 /* CDFIXME: remove this? */
219 write_c0_compare(read_c0_count() + (8* mips_hpt_frequency/HZ)); 168 write_c0_compare(read_c0_count() + (8* mips_hpt_frequency/HZ));
220 169
221#ifdef CONFIG_MIPS_MT_FPAFF 170#ifdef CONFIG_MIPS_MT_FPAFF
@@ -276,7 +225,7 @@ static void __cpuinit vsmp_boot_secondary(int cpu, struct task_struct *idle)
276/* 225/*
277 * Common setup before any secondaries are started 226 * Common setup before any secondaries are started
278 * Make sure all CPU's are in a sensible state before we boot any of the 227 * Make sure all CPU's are in a sensible state before we boot any of the
279 * secondarys 228 * secondaries
280 */ 229 */
281static void __init vsmp_smp_setup(void) 230static void __init vsmp_smp_setup(void)
282{ 231{
@@ -309,8 +258,8 @@ static void __init vsmp_smp_setup(void)
309 for (tc = 0; tc <= ntc; tc++) { 258 for (tc = 0; tc <= ntc; tc++) {
310 settc(tc); 259 settc(tc);
311 260
312 smp_tc_init(tc, mvpconf0); 261 smvp_tc_init(tc, mvpconf0);
313 ncpu = smp_vpe_init(tc, mvpconf0, ncpu); 262 ncpu = smvp_vpe_init(tc, mvpconf0, ncpu);
314 } 263 }
315 264
316 /* Release config state */ 265 /* Release config state */
@@ -324,21 +273,6 @@ static void __init vsmp_smp_setup(void)
324static void __init vsmp_prepare_cpus(unsigned int max_cpus) 273static void __init vsmp_prepare_cpus(unsigned int max_cpus)
325{ 274{
326 mips_mt_set_cpuoptions(); 275 mips_mt_set_cpuoptions();
327
328 /* set up ipi interrupts */
329 if (cpu_has_vint) {
330 set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch);
331 set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
332 }
333
334 cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
335 cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ;
336
337 setup_irq(cpu_ipi_resched_irq, &irq_resched);
338 setup_irq(cpu_ipi_call_irq, &irq_call);
339
340 set_irq_handler(cpu_ipi_resched_irq, handle_percpu_irq);
341 set_irq_handler(cpu_ipi_call_irq, handle_percpu_irq);
342} 276}
343 277
344struct plat_smp_ops vsmp_smp_ops = { 278struct plat_smp_ops vsmp_smp_ops = {
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 9d41dab90a80..33780cc61ce9 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -35,6 +35,7 @@
35#include <asm/atomic.h> 35#include <asm/atomic.h>
36#include <asm/cpu.h> 36#include <asm/cpu.h>
37#include <asm/processor.h> 37#include <asm/processor.h>
38#include <asm/r4k-timer.h>
38#include <asm/system.h> 39#include <asm/system.h>
39#include <asm/mmu_context.h> 40#include <asm/mmu_context.h>
40#include <asm/time.h> 41#include <asm/time.h>
@@ -125,6 +126,8 @@ asmlinkage __cpuinit void start_secondary(void)
125 126
126 cpu_set(cpu, cpu_callin_map); 127 cpu_set(cpu, cpu_callin_map);
127 128
129 synchronise_count_slave();
130
128 cpu_idle(); 131 cpu_idle();
129} 132}
130 133
@@ -287,6 +290,7 @@ void smp_send_stop(void)
287void __init smp_cpus_done(unsigned int max_cpus) 290void __init smp_cpus_done(unsigned int max_cpus)
288{ 291{
289 mp_ops->cpus_done(); 292 mp_ops->cpus_done();
293 synchronise_count_master();
290} 294}
291 295
292/* called from main before smp_init() */ 296/* called from main before smp_init() */
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index 4705b3c11e5f..3e863186cd22 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -331,7 +331,8 @@ static void smtc_tc_setup(int vpe, int tc, int cpu)
331 /* In general, all TCs should have the same cpu_data indications */ 331 /* In general, all TCs should have the same cpu_data indications */
332 memcpy(&cpu_data[cpu], &cpu_data[0], sizeof(struct cpuinfo_mips)); 332 memcpy(&cpu_data[cpu], &cpu_data[0], sizeof(struct cpuinfo_mips));
333 /* For 34Kf, start with TC/CPU 0 as sole owner of single FPU context */ 333 /* For 34Kf, start with TC/CPU 0 as sole owner of single FPU context */
334 if (cpu_data[0].cputype == CPU_34K) 334 if (cpu_data[0].cputype == CPU_34K ||
335 cpu_data[0].cputype == CPU_1004K)
335 cpu_data[cpu].options &= ~MIPS_CPU_FPU; 336 cpu_data[cpu].options &= ~MIPS_CPU_FPU;
336 cpu_data[cpu].vpe_id = vpe; 337 cpu_data[cpu].vpe_id = vpe;
337 cpu_data[cpu].tc_id = tc; 338 cpu_data[cpu].tc_id = tc;
diff --git a/arch/mips/kernel/sync-r4k.c b/arch/mips/kernel/sync-r4k.c
new file mode 100644
index 000000000000..9021108eb9c1
--- /dev/null
+++ b/arch/mips/kernel/sync-r4k.c
@@ -0,0 +1,159 @@
1/*
2 * Count register synchronisation.
3 *
4 * All CPUs will have their count registers synchronised to the CPU0 expirelo
5 * value. This can cause a small timewarp for CPU0. All other CPU's should
6 * not have done anything significant (but they may have had interrupts
7 * enabled briefly - prom_smp_finish() should not be responsible for enabling
8 * interrupts...)
9 *
10 * FIXME: broken for SMTC
11 */
12
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/irqflags.h>
16#include <linux/r4k-timer.h>
17
18#include <asm/atomic.h>
19#include <asm/barrier.h>
20#include <asm/cpumask.h>
21#include <asm/mipsregs.h>
22
23static atomic_t __initdata count_start_flag = ATOMIC_INIT(0);
24static atomic_t __initdata count_count_start = ATOMIC_INIT(0);
25static atomic_t __initdata count_count_stop = ATOMIC_INIT(0);
26
27#define COUNTON 100
28#define NR_LOOPS 5
29
30void __init synchronise_count_master(void)
31{
32 int i;
33 unsigned long flags;
34 unsigned int initcount;
35 int nslaves;
36
37#ifdef CONFIG_MIPS_MT_SMTC
38 /*
39 * SMTC needs to synchronise per VPE, not per CPU
40 * ignore for now
41 */
42 return;
43#endif
44
45 pr_info("Checking COUNT synchronization across %u CPUs: ",
46 num_online_cpus());
47
48 local_irq_save(flags);
49
50 /*
51 * Notify the slaves that it's time to start
52 */
53 atomic_set(&count_start_flag, 1);
54 smp_wmb();
55
56 /* Count will be initialised to expirelo for all CPU's */
57 initcount = expirelo;
58
59 /*
60 * We loop a few times to get a primed instruction cache,
61 * then the last pass is more or less synchronised and
62 * the master and slaves each set their cycle counters to a known
63 * value all at once. This reduces the chance of having random offsets
64 * between the processors, and guarantees that the maximum
65 * delay between the cycle counters is never bigger than
66 * the latency of information-passing (cachelines) between
67 * two CPUs.
68 */
69
70 nslaves = num_online_cpus()-1;
71 for (i = 0; i < NR_LOOPS; i++) {
72 /* slaves loop on '!= ncpus' */
73 while (atomic_read(&count_count_start) != nslaves)
74 mb();
75 atomic_set(&count_count_stop, 0);
76 smp_wmb();
77
78 /* this lets the slaves write their count register */
79 atomic_inc(&count_count_start);
80
81 /*
82 * Everyone initialises count in the last loop:
83 */
84 if (i == NR_LOOPS-1)
85 write_c0_count(initcount);
86
87 /*
88 * Wait for all slaves to leave the synchronization point:
89 */
90 while (atomic_read(&count_count_stop) != nslaves)
91 mb();
92 atomic_set(&count_count_start, 0);
93 smp_wmb();
94 atomic_inc(&count_count_stop);
95 }
96 /* Arrange for an interrupt in a short while */
97 write_c0_compare(read_c0_count() + COUNTON);
98
99 local_irq_restore(flags);
100
101 /*
102 * i386 code reported the skew here, but the
103 * count registers were almost certainly out of sync
104 * so no point in alarming people
105 */
106 printk("done.\n");
107}
108
109void __init synchronise_count_slave(void)
110{
111 int i;
112 unsigned long flags;
113 unsigned int initcount;
114 int ncpus;
115
116#ifdef CONFIG_MIPS_MT_SMTC
117 /*
118 * SMTC needs to synchronise per VPE, not per CPU
119 * ignore for now
120 */
121 return;
122#endif
123
124 local_irq_save(flags);
125
126 /*
127 * Not every cpu is online at the time this gets called,
128 * so we first wait for the master to say everyone is ready
129 */
130
131 while (!atomic_read(&count_start_flag))
132 mb();
133
134 /* Count will be initialised to expirelo for all CPU's */
135 initcount = expirelo;
136
137 ncpus = num_online_cpus();
138 for (i = 0; i < NR_LOOPS; i++) {
139 atomic_inc(&count_count_start);
140 while (atomic_read(&count_count_start) != ncpus)
141 mb();
142
143 /*
144 * Everyone initialises count in the last loop:
145 */
146 if (i == NR_LOOPS-1)
147 write_c0_count(initcount);
148
149 atomic_inc(&count_count_stop);
150 while (atomic_read(&count_count_stop) != ncpus)
151 mb();
152 }
153 /* Arrange for an interrupt in a short while */
154 write_c0_compare(read_c0_count() + COUNTON);
155
156 local_irq_restore(flags);
157}
158#undef NR_LOOPS
159#endif
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index d51f4e98455f..88185cd40c3b 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -22,6 +22,7 @@
22#include <linux/kallsyms.h> 22#include <linux/kallsyms.h>
23#include <linux/bootmem.h> 23#include <linux/bootmem.h>
24#include <linux/interrupt.h> 24#include <linux/interrupt.h>
25#include <linux/ptrace.h>
25 26
26#include <asm/bootinfo.h> 27#include <asm/bootinfo.h>
27#include <asm/branch.h> 28#include <asm/branch.h>
@@ -80,19 +81,22 @@ void (*board_bind_eic_interrupt)(int irq, int regset);
80 81
81static void show_raw_backtrace(unsigned long reg29) 82static void show_raw_backtrace(unsigned long reg29)
82{ 83{
83 unsigned long *sp = (unsigned long *)reg29; 84 unsigned long *sp = (unsigned long *)(reg29 & ~3);
84 unsigned long addr; 85 unsigned long addr;
85 86
86 printk("Call Trace:"); 87 printk("Call Trace:");
87#ifdef CONFIG_KALLSYMS 88#ifdef CONFIG_KALLSYMS
88 printk("\n"); 89 printk("\n");
89#endif 90#endif
90 while (!kstack_end(sp)) { 91#define IS_KVA01(a) ((((unsigned int)a) & 0xc0000000) == 0x80000000)
91 addr = *sp++; 92 if (IS_KVA01(sp)) {
92 if (__kernel_text_address(addr)) 93 while (!kstack_end(sp)) {
93 print_ip_sym(addr); 94 addr = *sp++;
95 if (__kernel_text_address(addr))
96 print_ip_sym(addr);
97 }
98 printk("\n");
94 } 99 }
95 printk("\n");
96} 100}
97 101
98#ifdef CONFIG_KALLSYMS 102#ifdef CONFIG_KALLSYMS
@@ -192,16 +196,19 @@ EXPORT_SYMBOL(dump_stack);
192static void show_code(unsigned int __user *pc) 196static void show_code(unsigned int __user *pc)
193{ 197{
194 long i; 198 long i;
199 unsigned short __user *pc16 = NULL;
195 200
196 printk("\nCode:"); 201 printk("\nCode:");
197 202
203 if ((unsigned long)pc & 1)
204 pc16 = (unsigned short __user *)((unsigned long)pc & ~1);
198 for(i = -3 ; i < 6 ; i++) { 205 for(i = -3 ; i < 6 ; i++) {
199 unsigned int insn; 206 unsigned int insn;
200 if (__get_user(insn, pc + i)) { 207 if (pc16 ? __get_user(insn, pc16 + i) : __get_user(insn, pc + i)) {
201 printk(" (Bad address in epc)\n"); 208 printk(" (Bad address in epc)\n");
202 break; 209 break;
203 } 210 }
204 printk("%c%08x%c", (i?' ':'<'), insn, (i?' ':'>')); 211 printk("%c%0*x%c", (i?' ':'<'), pc16 ? 4 : 8, insn, (i?' ':'>'));
205 } 212 }
206} 213}
207 214
@@ -311,10 +318,21 @@ void show_regs(struct pt_regs *regs)
311 318
312void show_registers(const struct pt_regs *regs) 319void show_registers(const struct pt_regs *regs)
313{ 320{
321 const int field = 2 * sizeof(unsigned long);
322
314 __show_regs(regs); 323 __show_regs(regs);
315 print_modules(); 324 print_modules();
316 printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n", 325 printk("Process %s (pid: %d, threadinfo=%p, task=%p, tls=%0*lx)\n",
317 current->comm, task_pid_nr(current), current_thread_info(), current); 326 current->comm, current->pid, current_thread_info(), current,
327 field, current_thread_info()->tp_value);
328 if (cpu_has_userlocal) {
329 unsigned long tls;
330
331 tls = read_c0_userlocal();
332 if (tls != current_thread_info()->tp_value)
333 printk("*HwTLS: %0*lx\n", field, tls);
334 }
335
318 show_stacktrace(current, regs); 336 show_stacktrace(current, regs);
319 show_code((unsigned int __user *) regs->cp0_epc); 337 show_code((unsigned int __user *) regs->cp0_epc);
320 printk("\n"); 338 printk("\n");
@@ -985,6 +1003,21 @@ asmlinkage void do_reserved(struct pt_regs *regs)
985 (regs->cp0_cause & 0x7f) >> 2); 1003 (regs->cp0_cause & 0x7f) >> 2);
986} 1004}
987 1005
1006static int __initdata l1parity = 1;
1007static int __init nol1parity(char *s)
1008{
1009 l1parity = 0;
1010 return 1;
1011}
1012__setup("nol1par", nol1parity);
1013static int __initdata l2parity = 1;
1014static int __init nol2parity(char *s)
1015{
1016 l2parity = 0;
1017 return 1;
1018}
1019__setup("nol2par", nol2parity);
1020
988/* 1021/*
989 * Some MIPS CPUs can enable/disable for cache parity detection, but do 1022 * Some MIPS CPUs can enable/disable for cache parity detection, but do
990 * it different ways. 1023 * it different ways.
@@ -994,6 +1027,62 @@ static inline void parity_protection_init(void)
994 switch (current_cpu_type()) { 1027 switch (current_cpu_type()) {
995 case CPU_24K: 1028 case CPU_24K:
996 case CPU_34K: 1029 case CPU_34K:
1030 case CPU_74K:
1031 case CPU_1004K:
1032 {
1033#define ERRCTL_PE 0x80000000
1034#define ERRCTL_L2P 0x00800000
1035 unsigned long errctl;
1036 unsigned int l1parity_present, l2parity_present;
1037
1038 errctl = read_c0_ecc();
1039 errctl &= ~(ERRCTL_PE|ERRCTL_L2P);
1040
1041 /* probe L1 parity support */
1042 write_c0_ecc(errctl | ERRCTL_PE);
1043 back_to_back_c0_hazard();
1044 l1parity_present = (read_c0_ecc() & ERRCTL_PE);
1045
1046 /* probe L2 parity support */
1047 write_c0_ecc(errctl|ERRCTL_L2P);
1048 back_to_back_c0_hazard();
1049 l2parity_present = (read_c0_ecc() & ERRCTL_L2P);
1050
1051 if (l1parity_present && l2parity_present) {
1052 if (l1parity)
1053 errctl |= ERRCTL_PE;
1054 if (l1parity ^ l2parity)
1055 errctl |= ERRCTL_L2P;
1056 } else if (l1parity_present) {
1057 if (l1parity)
1058 errctl |= ERRCTL_PE;
1059 } else if (l2parity_present) {
1060 if (l2parity)
1061 errctl |= ERRCTL_L2P;
1062 } else {
1063 /* No parity available */
1064 }
1065
1066 printk(KERN_INFO "Writing ErrCtl register=%08lx\n", errctl);
1067
1068 write_c0_ecc(errctl);
1069 back_to_back_c0_hazard();
1070 errctl = read_c0_ecc();
1071 printk(KERN_INFO "Readback ErrCtl register=%08lx\n", errctl);
1072
1073 if (l1parity_present)
1074 printk(KERN_INFO "Cache parity protection %sabled\n",
1075 (errctl & ERRCTL_PE) ? "en" : "dis");
1076
1077 if (l2parity_present) {
1078 if (l1parity_present && l1parity)
1079 errctl ^= ERRCTL_L2P;
1080 printk(KERN_INFO "L2 cache parity protection %sabled\n",
1081 (errctl & ERRCTL_L2P) ? "en" : "dis");
1082 }
1083 }
1084 break;
1085
997 case CPU_5KC: 1086 case CPU_5KC:
998 write_c0_ecc(0x80000000); 1087 write_c0_ecc(0x80000000);
999 back_to_back_c0_hazard(); 1088 back_to_back_c0_hazard();
@@ -1353,7 +1442,6 @@ void __cpuinit per_cpu_trap_init(void)
1353 change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX, 1442 change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX,
1354 status_set); 1443 status_set);
1355 1444
1356#ifdef CONFIG_CPU_MIPSR2
1357 if (cpu_has_mips_r2) { 1445 if (cpu_has_mips_r2) {
1358 unsigned int enable = 0x0000000f; 1446 unsigned int enable = 0x0000000f;
1359 1447
@@ -1362,7 +1450,6 @@ void __cpuinit per_cpu_trap_init(void)
1362 1450
1363 write_c0_hwrena(enable); 1451 write_c0_hwrena(enable);
1364 } 1452 }
1365#endif
1366 1453
1367#ifdef CONFIG_MIPS_MT_SMTC 1454#ifdef CONFIG_MIPS_MT_SMTC
1368 if (!secondaryTC) { 1455 if (!secondaryTC) {
diff --git a/arch/mips/mips-boards/generic/Makefile b/arch/mips/mips-boards/generic/Makefile
index b31d8dfed1be..f7f87fc09d1e 100644
--- a/arch/mips/mips-boards/generic/Makefile
+++ b/arch/mips/mips-boards/generic/Makefile
@@ -20,6 +20,7 @@
20 20
21obj-y := reset.o display.o init.o memory.o \ 21obj-y := reset.o display.o init.o memory.o \
22 cmdline.o time.o 22 cmdline.o time.o
23obj-y += amon.o
23 24
24obj-$(CONFIG_EARLY_PRINTK) += console.o 25obj-$(CONFIG_EARLY_PRINTK) += console.o
25obj-$(CONFIG_PCI) += pci.o 26obj-$(CONFIG_PCI) += pci.o
diff --git a/arch/mips/mips-boards/generic/amon.c b/arch/mips/mips-boards/generic/amon.c
new file mode 100644
index 000000000000..b7633fda4180
--- /dev/null
+++ b/arch/mips/mips-boards/generic/amon.c
@@ -0,0 +1,80 @@
1/*
2 * Copyright (C) 2007 MIPS Technologies, Inc.
3 * All rights reserved.
4
5 * This program is free software; you can distribute it and/or modify it
6 * under the terms of the GNU General Public License (Version 2) as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
17 *
18 * Arbitrary Monitor interface
19 */
20
21#include <linux/kernel.h>
22#include <linux/init.h>
23#include <linux/smp.h>
24
25#include <asm-mips/addrspace.h>
26#include <asm-mips/mips-boards/launch.h>
27#include <asm-mips/mipsmtregs.h>
28
29int amon_cpu_avail(int cpu)
30{
31 struct cpulaunch *launch = (struct cpulaunch *)KSEG0ADDR(CPULAUNCH);
32
33 if (cpu < 0 || cpu >= NCPULAUNCH) {
34 pr_debug("avail: cpu%d is out of range\n", cpu);
35 return 0;
36 }
37
38 launch += cpu;
39 if (!(launch->flags & LAUNCH_FREADY)) {
40 pr_debug("avail: cpu%d is not ready\n", cpu);
41 return 0;
42 }
43 if (launch->flags & (LAUNCH_FGO|LAUNCH_FGONE)) {
44 pr_debug("avail: too late.. cpu%d is already gone\n", cpu);
45 return 0;
46 }
47
48 return 1;
49}
50
51void amon_cpu_start(int cpu,
52 unsigned long pc, unsigned long sp,
53 unsigned long gp, unsigned long a0)
54{
55 volatile struct cpulaunch *launch =
56 (struct cpulaunch *)KSEG0ADDR(CPULAUNCH);
57
58 if (!amon_cpu_avail(cpu))
59 return;
60 if (cpu == smp_processor_id()) {
61 pr_debug("launch: I am cpu%d!\n", cpu);
62 return;
63 }
64 launch += cpu;
65
66 pr_debug("launch: starting cpu%d\n", cpu);
67
68 launch->pc = pc;
69 launch->gp = gp;
70 launch->sp = sp;
71 launch->a0 = a0;
72
73 /* Make sure target sees parameters before the go bit */
74 smp_mb();
75
76 launch->flags |= LAUNCH_FGO;
77 while ((launch->flags & LAUNCH_FGONE) == 0)
78 ;
79 pr_debug("launch: cpu%d gone!\n", cpu);
80}
diff --git a/arch/mips/mips-boards/generic/init.c b/arch/mips/mips-boards/generic/init.c
index 07671fb9074f..852b19492d8c 100644
--- a/arch/mips/mips-boards/generic/init.c
+++ b/arch/mips/mips-boards/generic/init.c
@@ -424,6 +424,9 @@ void __init prom_init(void)
424#ifdef CONFIG_SERIAL_8250_CONSOLE 424#ifdef CONFIG_SERIAL_8250_CONSOLE
425 console_config(); 425 console_config();
426#endif 426#endif
427#ifdef CONFIG_MIPS_CMP
428 register_smp_ops(&cmp_smp_ops);
429#endif
427#ifdef CONFIG_MIPS_MT_SMP 430#ifdef CONFIG_MIPS_MT_SMP
428 register_smp_ops(&vsmp_smp_ops); 431 register_smp_ops(&vsmp_smp_ops);
429#endif 432#endif
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c
index b50e0fc406ac..4fe62fca994e 100644
--- a/arch/mips/mips-boards/generic/time.c
+++ b/arch/mips/mips-boards/generic/time.c
@@ -55,16 +55,36 @@
55unsigned long cpu_khz; 55unsigned long cpu_khz;
56 56
57static int mips_cpu_timer_irq; 57static int mips_cpu_timer_irq;
58static int mips_cpu_perf_irq;
58extern int cp0_perfcount_irq; 59extern int cp0_perfcount_irq;
59 60
61DEFINE_PER_CPU(unsigned int, tickcount);
62#define tickcount_this_cpu __get_cpu_var(tickcount)
63static unsigned long ledbitmask;
64
60static void mips_timer_dispatch(void) 65static void mips_timer_dispatch(void)
61{ 66{
67#if defined(CONFIG_MIPS_MALTA) || defined(CONFIG_MIPS_ATLAS)
68 /*
69 * Yes, this is very tacky, won't work as expected with SMTC and
70 * dyntick will break it,
71 * but it gives me a nice warm feeling during debug
72 */
73#define LEDBAR 0xbf000408
74 if (tickcount_this_cpu++ >= HZ) {
75 tickcount_this_cpu = 0;
76 change_bit(smp_processor_id(), &ledbitmask);
77 smp_wmb(); /* Make sure every one else sees the change */
78 /* This will pick up any recent changes made by other CPU's */
79 *(unsigned int *)LEDBAR = ledbitmask;
80 }
81#endif
62 do_IRQ(mips_cpu_timer_irq); 82 do_IRQ(mips_cpu_timer_irq);
63} 83}
64 84
65static void mips_perf_dispatch(void) 85static void mips_perf_dispatch(void)
66{ 86{
67 do_IRQ(cp0_perfcount_irq); 87 do_IRQ(mips_cpu_perf_irq);
68} 88}
69 89
70/* 90/*
@@ -129,19 +149,18 @@ unsigned long read_persistent_clock(void)
129 149
130void __init plat_perf_setup(void) 150void __init plat_perf_setup(void)
131{ 151{
132 cp0_perfcount_irq = -1;
133
134#ifdef MSC01E_INT_BASE 152#ifdef MSC01E_INT_BASE
135 if (cpu_has_veic) { 153 if (cpu_has_veic) {
136 set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch); 154 set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch);
137 cp0_perfcount_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR; 155 mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
138 } else 156 } else
139#endif 157#endif
140 if (cp0_perfcount_irq >= 0) { 158 if (cp0_perfcount_irq >= 0) {
141 if (cpu_has_vint) 159 if (cpu_has_vint)
142 set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch); 160 set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch);
161 mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
143#ifdef CONFIG_SMP 162#ifdef CONFIG_SMP
144 set_irq_handler(cp0_perfcount_irq, handle_percpu_irq); 163 set_irq_handler(mips_cpu_perf_irq, handle_percpu_irq);
145#endif 164#endif
146 } 165 }
147} 166}
diff --git a/arch/mips/mips-boards/malta/Makefile b/arch/mips/mips-boards/malta/Makefile
index 931ca4600a63..8dc6e2ac4c03 100644
--- a/arch/mips/mips-boards/malta/Makefile
+++ b/arch/mips/mips-boards/malta/Makefile
@@ -22,6 +22,7 @@
22obj-y := malta_int.o malta_platform.o malta_setup.o 22obj-y := malta_int.o malta_platform.o malta_setup.o
23 23
24obj-$(CONFIG_MTD) += malta_mtd.o 24obj-$(CONFIG_MTD) += malta_mtd.o
25# FIXME FIXME FIXME
25obj-$(CONFIG_MIPS_MT_SMTC) += malta_smtc.o 26obj-$(CONFIG_MIPS_MT_SMTC) += malta_smtc.o
26 27
27EXTRA_CFLAGS += -Werror 28EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c
index dbe60eb55e29..e1744ae855ce 100644
--- a/arch/mips/mips-boards/malta/malta_int.c
+++ b/arch/mips/mips-boards/malta/malta_int.c
@@ -31,6 +31,7 @@
31#include <linux/kernel.h> 31#include <linux/kernel.h>
32#include <linux/random.h> 32#include <linux/random.h>
33 33
34#include <asm/traps.h>
34#include <asm/i8259.h> 35#include <asm/i8259.h>
35#include <asm/irq_cpu.h> 36#include <asm/irq_cpu.h>
36#include <asm/irq_regs.h> 37#include <asm/irq_regs.h>
@@ -41,6 +42,14 @@
41#include <asm/mips-boards/generic.h> 42#include <asm/mips-boards/generic.h>
42#include <asm/mips-boards/msc01_pci.h> 43#include <asm/mips-boards/msc01_pci.h>
43#include <asm/msc01_ic.h> 44#include <asm/msc01_ic.h>
45#include <asm/gic.h>
46#include <asm/gcmpregs.h>
47
48int gcmp_present = -1;
49int gic_present;
50static unsigned long _msc01_biu_base;
51static unsigned long _gcmp_base;
52static unsigned int ipi_map[NR_CPUS];
44 53
45static DEFINE_SPINLOCK(mips_irq_lock); 54static DEFINE_SPINLOCK(mips_irq_lock);
46 55
@@ -121,6 +130,17 @@ static void malta_hw0_irqdispatch(void)
121 do_IRQ(MALTA_INT_BASE + irq); 130 do_IRQ(MALTA_INT_BASE + irq);
122} 131}
123 132
133static void malta_ipi_irqdispatch(void)
134{
135 int irq;
136
137 irq = gic_get_int();
138 if (irq < 0)
139 return; /* interrupt has already been cleared */
140
141 do_IRQ(MIPS_GIC_IRQ_BASE + irq);
142}
143
124static void corehi_irqdispatch(void) 144static void corehi_irqdispatch(void)
125{ 145{
126 unsigned int intedge, intsteer, pcicmd, pcibadaddr; 146 unsigned int intedge, intsteer, pcicmd, pcibadaddr;
@@ -257,12 +277,61 @@ asmlinkage void plat_irq_dispatch(void)
257 277
258 if (irq == MIPSCPU_INT_I8259A) 278 if (irq == MIPSCPU_INT_I8259A)
259 malta_hw0_irqdispatch(); 279 malta_hw0_irqdispatch();
280 else if (gic_present && ((1 << irq) & ipi_map[smp_processor_id()]))
281 malta_ipi_irqdispatch();
260 else if (irq >= 0) 282 else if (irq >= 0)
261 do_IRQ(MIPS_CPU_IRQ_BASE + irq); 283 do_IRQ(MIPS_CPU_IRQ_BASE + irq);
262 else 284 else
263 spurious_interrupt(); 285 spurious_interrupt();
264} 286}
265 287
288#ifdef CONFIG_MIPS_MT_SMP
289
290
291#define GIC_MIPS_CPU_IPI_RESCHED_IRQ 3
292#define GIC_MIPS_CPU_IPI_CALL_IRQ 4
293
294#define MIPS_CPU_IPI_RESCHED_IRQ 0 /* SW int 0 for resched */
295#define C_RESCHED C_SW0
296#define MIPS_CPU_IPI_CALL_IRQ 1 /* SW int 1 for resched */
297#define C_CALL C_SW1
298static int cpu_ipi_resched_irq, cpu_ipi_call_irq;
299
300static void ipi_resched_dispatch(void)
301{
302 do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ);
303}
304
305static void ipi_call_dispatch(void)
306{
307 do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ);
308}
309
310static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
311{
312 return IRQ_HANDLED;
313}
314
315static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
316{
317 smp_call_function_interrupt();
318
319 return IRQ_HANDLED;
320}
321
322static struct irqaction irq_resched = {
323 .handler = ipi_resched_interrupt,
324 .flags = IRQF_DISABLED|IRQF_PERCPU,
325 .name = "IPI_resched"
326};
327
328static struct irqaction irq_call = {
329 .handler = ipi_call_interrupt,
330 .flags = IRQF_DISABLED|IRQF_PERCPU,
331 .name = "IPI_call"
332};
333#endif /* CONFIG_MIPS_MT_SMP */
334
266static struct irqaction i8259irq = { 335static struct irqaction i8259irq = {
267 .handler = no_action, 336 .handler = no_action,
268 .name = "XT-PIC cascade" 337 .name = "XT-PIC cascade"
@@ -291,15 +360,90 @@ msc_irqmap_t __initdata msc_eicirqmap[] = {
291 {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0}, 360 {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0},
292 {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0} 361 {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0}
293}; 362};
363
294int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap); 364int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap);
295 365
366/*
367 * This GIC specific tabular array defines the association between External
368 * Interrupts and CPUs/Core Interrupts. The nature of the External
369 * Interrupts is also defined here - polarity/trigger.
370 */
371static struct gic_intr_map gic_intr_map[] = {
372 { GIC_EXT_INTR(0), X, X, X, X, 0 },
373 { GIC_EXT_INTR(1), X, X, X, X, 0 },
374 { GIC_EXT_INTR(2), X, X, X, X, 0 },
375 { GIC_EXT_INTR(3), 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
376 { GIC_EXT_INTR(4), 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
377 { GIC_EXT_INTR(5), 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
378 { GIC_EXT_INTR(6), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
379 { GIC_EXT_INTR(7), 0, GIC_CPU_INT4, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
380 { GIC_EXT_INTR(8), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
381 { GIC_EXT_INTR(9), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
382 { GIC_EXT_INTR(10), X, X, X, X, 0 },
383 { GIC_EXT_INTR(11), X, X, X, X, 0 },
384 { GIC_EXT_INTR(12), 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
385 { GIC_EXT_INTR(13), 0, GIC_MAP_TO_NMI_MSK, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
386 { GIC_EXT_INTR(14), 0, GIC_MAP_TO_NMI_MSK, GIC_POL_POS, GIC_TRIG_LEVEL, 0 },
387 { GIC_EXT_INTR(15), X, X, X, X, 0 },
388 { GIC_EXT_INTR(16), 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
389 { GIC_EXT_INTR(17), 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
390 { GIC_EXT_INTR(18), 1, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
391 { GIC_EXT_INTR(19), 1, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
392 { GIC_EXT_INTR(20), 2, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
393 { GIC_EXT_INTR(21), 2, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
394 { GIC_EXT_INTR(22), 3, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
395 { GIC_EXT_INTR(23), 3, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_EDGE, 1 },
396};
397
398/*
399 * GCMP needs to be detected before any SMP initialisation
400 */
401int __init gcmp_probe(unsigned long addr, unsigned long size)
402{
403 if (gcmp_present >= 0)
404 return gcmp_present;
405
406 _gcmp_base = (unsigned long) ioremap_nocache(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ);
407 _msc01_biu_base = (unsigned long) ioremap_nocache(MSC01_BIU_REG_BASE, MSC01_BIU_ADDRSPACE_SZ);
408 gcmp_present = (GCMPGCB(GCMPB) & GCMP_GCB_GCMPB_GCMPBASE_MSK) == GCMP_BASE_ADDR;
409
410 if (gcmp_present)
411 printk(KERN_DEBUG "GCMP present\n");
412 return gcmp_present;
413}
414
415void __init fill_ipi_map(void)
416{
417 int i;
418
419 for (i = 0; i < ARRAY_SIZE(gic_intr_map); i++) {
420 if (gic_intr_map[i].ipiflag && (gic_intr_map[i].cpunum != X))
421 ipi_map[gic_intr_map[i].cpunum] |=
422 (1 << (gic_intr_map[i].pin + 2));
423 }
424}
425
296void __init arch_init_irq(void) 426void __init arch_init_irq(void)
297{ 427{
428 int gic_present, gcmp_present;
429
298 init_i8259_irqs(); 430 init_i8259_irqs();
299 431
300 if (!cpu_has_veic) 432 if (!cpu_has_veic)
301 mips_cpu_irq_init(); 433 mips_cpu_irq_init();
302 434
435 gcmp_present = gcmp_probe(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ);
436 if (gcmp_present) {
437 GCMPGCB(GICBA) = GIC_BASE_ADDR | GCMP_GCB_GICBA_EN_MSK;
438 gic_present = 1;
439 } else {
440 _msc01_biu_base = (unsigned long) ioremap_nocache(MSC01_BIU_REG_BASE, MSC01_BIU_ADDRSPACE_SZ);
441 gic_present = (REG(_msc01_biu_base, MSC01_SC_CFG) &
442 MSC01_SC_CFG_GICPRES_MSK) >> MSC01_SC_CFG_GICPRES_SHF;
443 }
444 if (gic_present)
445 printk(KERN_DEBUG "GIC present\n");
446
303 switch (mips_revision_sconid) { 447 switch (mips_revision_sconid) {
304 case MIPS_REVISION_SCON_SOCIT: 448 case MIPS_REVISION_SCON_SOCIT:
305 case MIPS_REVISION_SCON_ROCIT: 449 case MIPS_REVISION_SCON_ROCIT:
@@ -360,4 +504,206 @@ void __init arch_init_irq(void)
360 setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI, 504 setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI,
361 &corehi_irqaction); 505 &corehi_irqaction);
362 } 506 }
507
508#if defined(CONFIG_MIPS_MT_SMP)
509 if (gic_present) {
510 /* FIXME */
511 int i;
512 struct {
513 unsigned int resched;
514 unsigned int call;
515 } ipiirq[] = {
516 {
517 .resched = GIC_IPI_EXT_INTR_RESCHED_VPE0,
518 .call = GIC_IPI_EXT_INTR_CALLFNC_VPE0},
519 {
520 .resched = GIC_IPI_EXT_INTR_RESCHED_VPE1,
521 .call = GIC_IPI_EXT_INTR_CALLFNC_VPE1
522 }, {
523 .resched = GIC_IPI_EXT_INTR_RESCHED_VPE2,
524 .call = GIC_IPI_EXT_INTR_CALLFNC_VPE2
525 }, {
526 .resched = GIC_IPI_EXT_INTR_RESCHED_VPE3,
527 .call = GIC_IPI_EXT_INTR_CALLFNC_VPE3
528 }
529 };
530#define NIPI (sizeof(ipiirq)/sizeof(ipiirq[0]))
531 fill_ipi_map();
532 gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map, ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE);
533 if (!gcmp_present) {
534 /* Enable the GIC */
535 i = REG(_msc01_biu_base, MSC01_SC_CFG);
536 REG(_msc01_biu_base, MSC01_SC_CFG) =
537 (i | (0x1 << MSC01_SC_CFG_GICENA_SHF));
538 pr_debug("GIC Enabled\n");
539 }
540
541 /* set up ipi interrupts */
542 if (cpu_has_vint) {
543 set_vi_handler(MIPSCPU_INT_IPI0, malta_ipi_irqdispatch);
544 set_vi_handler(MIPSCPU_INT_IPI1, malta_ipi_irqdispatch);
545 }
546 /* Argh.. this really needs sorting out.. */
547 printk("CPU%d: status register was %08x\n", smp_processor_id(), read_c0_status());
548 write_c0_status(read_c0_status() | STATUSF_IP3 | STATUSF_IP4);
549 printk("CPU%d: status register now %08x\n", smp_processor_id(), read_c0_status());
550 write_c0_status(0x1100dc00);
551 printk("CPU%d: status register frc %08x\n", smp_processor_id(), read_c0_status());
552 for (i = 0; i < NIPI; i++) {
553 setup_irq(MIPS_GIC_IRQ_BASE + ipiirq[i].resched, &irq_resched);
554 setup_irq(MIPS_GIC_IRQ_BASE + ipiirq[i].call, &irq_call);
555
556 set_irq_handler(MIPS_GIC_IRQ_BASE + ipiirq[i].resched, handle_percpu_irq);
557 set_irq_handler(MIPS_GIC_IRQ_BASE + ipiirq[i].call, handle_percpu_irq);
558 }
559 } else {
560 /* set up ipi interrupts */
561 if (cpu_has_veic) {
562 set_vi_handler (MSC01E_INT_SW0, ipi_resched_dispatch);
563 set_vi_handler (MSC01E_INT_SW1, ipi_call_dispatch);
564 cpu_ipi_resched_irq = MSC01E_INT_SW0;
565 cpu_ipi_call_irq = MSC01E_INT_SW1;
566 } else {
567 if (cpu_has_vint) {
568 set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch);
569 set_vi_handler (MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
570 }
571 cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
572 cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ;
573 }
574
575 setup_irq(cpu_ipi_resched_irq, &irq_resched);
576 setup_irq(cpu_ipi_call_irq, &irq_call);
577
578 set_irq_handler(cpu_ipi_resched_irq, handle_percpu_irq);
579 set_irq_handler(cpu_ipi_call_irq, handle_percpu_irq);
580 }
581#endif
582}
583
584void malta_be_init(void)
585{
586 if (gcmp_present) {
587 /* Could change CM error mask register */
588 }
589}
590
591
592static char *tr[8] = {
593 "mem", "gcr", "gic", "mmio",
594 "0x04", "0x05", "0x06", "0x07"
595};
596
597static char *mcmd[32] = {
598 [0x00] = "0x00",
599 [0x01] = "Legacy Write",
600 [0x02] = "Legacy Read",
601 [0x03] = "0x03",
602 [0x04] = "0x04",
603 [0x05] = "0x05",
604 [0x06] = "0x06",
605 [0x07] = "0x07",
606 [0x08] = "Coherent Read Own",
607 [0x09] = "Coherent Read Share",
608 [0x0a] = "Coherent Read Discard",
609 [0x0b] = "Coherent Ready Share Always",
610 [0x0c] = "Coherent Upgrade",
611 [0x0d] = "Coherent Writeback",
612 [0x0e] = "0x0e",
613 [0x0f] = "0x0f",
614 [0x10] = "Coherent Copyback",
615 [0x11] = "Coherent Copyback Invalidate",
616 [0x12] = "Coherent Invalidate",
617 [0x13] = "Coherent Write Invalidate",
618 [0x14] = "Coherent Completion Sync",
619 [0x15] = "0x15",
620 [0x16] = "0x16",
621 [0x17] = "0x17",
622 [0x18] = "0x18",
623 [0x19] = "0x19",
624 [0x1a] = "0x1a",
625 [0x1b] = "0x1b",
626 [0x1c] = "0x1c",
627 [0x1d] = "0x1d",
628 [0x1e] = "0x1e",
629 [0x1f] = "0x1f"
630};
631
632static char *core[8] = {
633 "Invalid/OK", "Invalid/Data",
634 "Shared/OK", "Shared/Data",
635 "Modified/OK", "Modified/Data",
636 "Exclusive/OK", "Exclusive/Data"
637};
638
639static char *causes[32] = {
640 "None", "GC_WR_ERR", "GC_RD_ERR", "COH_WR_ERR",
641 "COH_RD_ERR", "MMIO_WR_ERR", "MMIO_RD_ERR", "0x07",
642 "0x08", "0x09", "0x0a", "0x0b",
643 "0x0c", "0x0d", "0x0e", "0x0f",
644 "0x10", "0x11", "0x12", "0x13",
645 "0x14", "0x15", "0x16", "INTVN_WR_ERR",
646 "INTVN_RD_ERR", "0x19", "0x1a", "0x1b",
647 "0x1c", "0x1d", "0x1e", "0x1f"
648};
649
650int malta_be_handler(struct pt_regs *regs, int is_fixup)
651{
652 /* This duplicates the handling in do_be which seems wrong */
653 int retval = is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL;
654
655 if (gcmp_present) {
656 unsigned long cm_error = GCMPGCB(GCMEC);
657 unsigned long cm_addr = GCMPGCB(GCMEA);
658 unsigned long cm_other = GCMPGCB(GCMEO);
659 unsigned long cause, ocause;
660 char buf[256];
661
662 cause = (cm_error & GCMP_GCB_GMEC_ERROR_TYPE_MSK);
663 if (cause != 0) {
664 cause >>= GCMP_GCB_GMEC_ERROR_TYPE_SHF;
665 if (cause < 16) {
666 unsigned long cca_bits = (cm_error >> 15) & 7;
667 unsigned long tr_bits = (cm_error >> 12) & 7;
668 unsigned long mcmd_bits = (cm_error >> 7) & 0x1f;
669 unsigned long stag_bits = (cm_error >> 3) & 15;
670 unsigned long sport_bits = (cm_error >> 0) & 7;
671
672 snprintf(buf, sizeof(buf),
673 "CCA=%lu TR=%s MCmd=%s STag=%lu "
674 "SPort=%lu\n",
675 cca_bits, tr[tr_bits], mcmd[mcmd_bits],
676 stag_bits, sport_bits);
677 } else {
678 /* glob state & sresp together */
679 unsigned long c3_bits = (cm_error >> 18) & 7;
680 unsigned long c2_bits = (cm_error >> 15) & 7;
681 unsigned long c1_bits = (cm_error >> 12) & 7;
682 unsigned long c0_bits = (cm_error >> 9) & 7;
683 unsigned long sc_bit = (cm_error >> 8) & 1;
684 unsigned long mcmd_bits = (cm_error >> 3) & 0x1f;
685 unsigned long sport_bits = (cm_error >> 0) & 7;
686 snprintf(buf, sizeof(buf),
687 "C3=%s C2=%s C1=%s C0=%s SC=%s "
688 "MCmd=%s SPort=%lu\n",
689 core[c3_bits], core[c2_bits],
690 core[c1_bits], core[c0_bits],
691 sc_bit ? "True" : "False",
692 mcmd[mcmd_bits], sport_bits);
693 }
694
695 ocause = (cm_other & GCMP_GCB_GMEO_ERROR_2ND_MSK) >>
696 GCMP_GCB_GMEO_ERROR_2ND_SHF;
697
698 printk("CM_ERROR=%08lx %s <%s>\n", cm_error,
699 causes[cause], buf);
700 printk("CM_ADDR =%08lx\n", cm_addr);
701 printk("CM_OTHER=%08lx %s\n", cm_other, causes[ocause]);
702
703 /* reprime cause register */
704 GCMPGCB(GCMEC) = 0;
705 }
706 }
707
708 return retval;
363} 709}
diff --git a/arch/mips/mips-boards/malta/malta_setup.c b/arch/mips/mips-boards/malta/malta_setup.c
index 2cd8f5734b36..4a0f21c76e7b 100644
--- a/arch/mips/mips-boards/malta/malta_setup.c
+++ b/arch/mips/mips-boards/malta/malta_setup.c
@@ -36,6 +36,9 @@
36#include <linux/console.h> 36#include <linux/console.h>
37#endif 37#endif
38 38
39extern void malta_be_init(void);
40extern int malta_be_handler(struct pt_regs *regs, int is_fixup);
41
39struct resource standard_io_resources[] = { 42struct resource standard_io_resources[] = {
40 { 43 {
41 .name = "dma1", 44 .name = "dma1",
@@ -220,4 +223,7 @@ void __init plat_mem_setup(void)
220 screen_info_setup(); 223 screen_info_setup();
221#endif 224#endif
222 mips_reboot_setup(); 225 mips_reboot_setup();
226
227 board_be_init = malta_be_init;
228 board_be_handler = malta_be_handler;
223} 229}
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 3d3e53651341..643c8bcffff3 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -54,6 +54,12 @@ static inline void r4k_on_each_cpu(void (*func) (void *info), void *info,
54 preempt_enable(); 54 preempt_enable();
55} 55}
56 56
57#if defined(CONFIG_MIPS_CMP)
58#define cpu_has_safe_index_cacheops 0
59#else
60#define cpu_has_safe_index_cacheops 1
61#endif
62
57/* 63/*
58 * Must die. 64 * Must die.
59 */ 65 */
@@ -482,6 +488,8 @@ static inline void local_r4k_flush_cache_page(void *args)
482 488
483 if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) { 489 if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) {
484 r4k_blast_dcache_page(addr); 490 r4k_blast_dcache_page(addr);
491 if (exec && !cpu_icache_snoops_remote_store)
492 r4k_blast_scache_page(addr);
485 } 493 }
486 if (exec) { 494 if (exec) {
487 if (vaddr && cpu_has_vtag_icache && mm == current->active_mm) { 495 if (vaddr && cpu_has_vtag_icache && mm == current->active_mm) {
@@ -584,7 +592,7 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
584 * subset property so we have to flush the primary caches 592 * subset property so we have to flush the primary caches
585 * explicitly 593 * explicitly
586 */ 594 */
587 if (size >= dcache_size) { 595 if (cpu_has_safe_index_cacheops && size >= dcache_size) {
588 r4k_blast_dcache(); 596 r4k_blast_dcache();
589 } else { 597 } else {
590 R4600_HIT_CACHEOP_WAR_IMPL; 598 R4600_HIT_CACHEOP_WAR_IMPL;
@@ -607,7 +615,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
607 return; 615 return;
608 } 616 }
609 617
610 if (size >= dcache_size) { 618 if (cpu_has_safe_index_cacheops && size >= dcache_size) {
611 r4k_blast_dcache(); 619 r4k_blast_dcache();
612 } else { 620 } else {
613 R4600_HIT_CACHEOP_WAR_IMPL; 621 R4600_HIT_CACHEOP_WAR_IMPL;
@@ -969,6 +977,7 @@ static void __cpuinit probe_pcache(void)
969 case CPU_24K: 977 case CPU_24K:
970 case CPU_34K: 978 case CPU_34K:
971 case CPU_74K: 979 case CPU_74K:
980 case CPU_1004K:
972 if ((read_c0_config7() & (1 << 16))) { 981 if ((read_c0_config7() & (1 << 16))) {
973 /* effectively physically indexed dcache, 982 /* effectively physically indexed dcache,
974 thus no virtual aliases. */ 983 thus no virtual aliases. */
@@ -1265,6 +1274,20 @@ static void __cpuinit coherency_setup(void)
1265 } 1274 }
1266} 1275}
1267 1276
1277#if defined(CONFIG_DMA_NONCOHERENT)
1278
1279static int __cpuinitdata coherentio;
1280
1281static int __init setcoherentio(char *str)
1282{
1283 coherentio = 1;
1284
1285 return 1;
1286}
1287
1288__setup("coherentio", setcoherentio);
1289#endif
1290
1268void __cpuinit r4k_cache_init(void) 1291void __cpuinit r4k_cache_init(void)
1269{ 1292{
1270 extern void build_clear_page(void); 1293 extern void build_clear_page(void);
@@ -1324,14 +1347,22 @@ void __cpuinit r4k_cache_init(void)
1324 flush_data_cache_page = r4k_flush_data_cache_page; 1347 flush_data_cache_page = r4k_flush_data_cache_page;
1325 flush_icache_range = r4k_flush_icache_range; 1348 flush_icache_range = r4k_flush_icache_range;
1326 1349
1327#ifdef CONFIG_DMA_NONCOHERENT 1350#if defined(CONFIG_DMA_NONCOHERENT)
1328 _dma_cache_wback_inv = r4k_dma_cache_wback_inv; 1351 if (coherentio) {
1329 _dma_cache_wback = r4k_dma_cache_wback_inv; 1352 _dma_cache_wback_inv = (void *)cache_noop;
1330 _dma_cache_inv = r4k_dma_cache_inv; 1353 _dma_cache_wback = (void *)cache_noop;
1354 _dma_cache_inv = (void *)cache_noop;
1355 } else {
1356 _dma_cache_wback_inv = r4k_dma_cache_wback_inv;
1357 _dma_cache_wback = r4k_dma_cache_wback_inv;
1358 _dma_cache_inv = r4k_dma_cache_inv;
1359 }
1331#endif 1360#endif
1332 1361
1333 build_clear_page(); 1362 build_clear_page();
1334 build_copy_page(); 1363 build_copy_page();
1364#if !defined(CONFIG_MIPS_CMP)
1335 local_r4k___flush_cache_all(NULL); 1365 local_r4k___flush_cache_all(NULL);
1366#endif
1336 coherency_setup(); 1367 coherency_setup();
1337} 1368}
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 235833af3a8b..05ac6c6123ca 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -221,7 +221,7 @@ void copy_user_highpage(struct page *to, struct page *from,
221 copy_page(vto, vfrom); 221 copy_page(vto, vfrom);
222 kunmap_atomic(vfrom, KM_USER0); 222 kunmap_atomic(vfrom, KM_USER0);
223 } 223 }
224 if (((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc) || 224 if ((!cpu_has_ic_fills_f_dc) ||
225 pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK)) 225 pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK))
226 flush_data_cache_page((unsigned long)vto); 226 flush_data_cache_page((unsigned long)vto);
227 kunmap_atomic(vto, KM_USER1); 227 kunmap_atomic(vto, KM_USER1);
diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c
index aa52aa146cea..b5f6f71b27bc 100644
--- a/arch/mips/oprofile/common.c
+++ b/arch/mips/oprofile/common.c
@@ -80,6 +80,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
80 case CPU_24K: 80 case CPU_24K:
81 case CPU_25KF: 81 case CPU_25KF:
82 case CPU_34K: 82 case CPU_34K:
83 case CPU_1004K:
83 case CPU_74K: 84 case CPU_74K:
84 case CPU_SB1: 85 case CPU_SB1:
85 case CPU_SB1A: 86 case CPU_SB1A:
diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c
index ccbea229a0e6..ca65469d7e30 100644
--- a/arch/mips/oprofile/op_model_mipsxx.c
+++ b/arch/mips/oprofile/op_model_mipsxx.c
@@ -32,8 +32,11 @@
32#define M_COUNTER_OVERFLOW (1UL << 31) 32#define M_COUNTER_OVERFLOW (1UL << 31)
33 33
34#ifdef CONFIG_MIPS_MT_SMP 34#ifdef CONFIG_MIPS_MT_SMP
35#define WHAT (M_TC_EN_VPE | M_PERFCTL_VPEID(smp_processor_id())) 35static int cpu_has_mipsmt_pertccounters;
36#define vpe_id() smp_processor_id() 36#define WHAT (M_TC_EN_VPE | \
37 M_PERFCTL_VPEID(cpu_data[smp_processor_id()].vpe_id))
38#define vpe_id() (cpu_has_mipsmt_pertccounters ? \
39 0 : cpu_data[smp_processor_id()].vpe_id)
37 40
38/* 41/*
39 * The number of bits to shift to convert between counters per core and 42 * The number of bits to shift to convert between counters per core and
@@ -243,11 +246,11 @@ static inline int __n_counters(void)
243{ 246{
244 if (!(read_c0_config1() & M_CONFIG1_PC)) 247 if (!(read_c0_config1() & M_CONFIG1_PC))
245 return 0; 248 return 0;
246 if (!(r_c0_perfctrl0() & M_PERFCTL_MORE)) 249 if (!(read_c0_perfctrl0() & M_PERFCTL_MORE))
247 return 1; 250 return 1;
248 if (!(r_c0_perfctrl1() & M_PERFCTL_MORE)) 251 if (!(read_c0_perfctrl1() & M_PERFCTL_MORE))
249 return 2; 252 return 2;
250 if (!(r_c0_perfctrl2() & M_PERFCTL_MORE)) 253 if (!(read_c0_perfctrl2() & M_PERFCTL_MORE))
251 return 3; 254 return 3;
252 255
253 return 4; 256 return 4;
@@ -274,8 +277,9 @@ static inline int n_counters(void)
274 return counters; 277 return counters;
275} 278}
276 279
277static inline void reset_counters(int counters) 280static void reset_counters(void *arg)
278{ 281{
282 int counters = (int)arg;
279 switch (counters) { 283 switch (counters) {
280 case 4: 284 case 4:
281 w_c0_perfctrl3(0); 285 w_c0_perfctrl3(0);
@@ -302,9 +306,12 @@ static int __init mipsxx_init(void)
302 return -ENODEV; 306 return -ENODEV;
303 } 307 }
304 308
305 reset_counters(counters); 309#ifdef CONFIG_MIPS_MT_SMP
306 310 cpu_has_mipsmt_pertccounters = read_c0_config7() & (1<<19);
307 counters = counters_total_to_per_cpu(counters); 311 if (!cpu_has_mipsmt_pertccounters)
312 counters = counters_total_to_per_cpu(counters);
313#endif
314 on_each_cpu(reset_counters, (void *)counters, 0, 1);
308 315
309 op_model_mipsxx_ops.num_counters = counters; 316 op_model_mipsxx_ops.num_counters = counters;
310 switch (current_cpu_type()) { 317 switch (current_cpu_type()) {
@@ -320,6 +327,13 @@ static int __init mipsxx_init(void)
320 op_model_mipsxx_ops.cpu_type = "mips/25K"; 327 op_model_mipsxx_ops.cpu_type = "mips/25K";
321 break; 328 break;
322 329
330 case CPU_1004K:
331#if 0
332 /* FIXME: report as 34K for now */
333 op_model_mipsxx_ops.cpu_type = "mips/1004K";
334 break;
335#endif
336
323 case CPU_34K: 337 case CPU_34K:
324 op_model_mipsxx_ops.cpu_type = "mips/34K"; 338 op_model_mipsxx_ops.cpu_type = "mips/34K";
325 break; 339 break;
@@ -365,7 +379,7 @@ static void mipsxx_exit(void)
365 int counters = op_model_mipsxx_ops.num_counters; 379 int counters = op_model_mipsxx_ops.num_counters;
366 380
367 counters = counters_per_cpu_to_total(counters); 381 counters = counters_per_cpu_to_total(counters);
368 reset_counters(counters); 382 on_each_cpu(reset_counters, (void *)counters, 0, 1);
369 383
370 perf_irq = null_perf_irq; 384 perf_irq = null_perf_irq;
371} 385}