diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2008-04-28 12:14:26 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2008-04-28 12:14:26 -0400 |
commit | 39b8d5254246ac56342b72f812255c8f7a74dca9 (patch) | |
tree | a9ec6bfb5d09a8367c34cc2067328d1b49bb46c1 /arch | |
parent | 308402445e005a039a72b315cd9b5ceeaea0063c (diff) |
[MIPS] Add support for MIPS CMP platform.
Signed-off-by: Chris Dearman <chris@mips.com>
Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips/Kconfig | 18 | ||||
-rw-r--r-- | arch/mips/kernel/Makefile | 3 | ||||
-rw-r--r-- | arch/mips/kernel/cpu-probe.c | 5 | ||||
-rw-r--r-- | arch/mips/kernel/irq-gic.c | 295 | ||||
-rw-r--r-- | arch/mips/kernel/smp-cmp.c | 265 | ||||
-rw-r--r-- | arch/mips/kernel/smp-mt.c | 96 | ||||
-rw-r--r-- | arch/mips/kernel/smp.c | 4 | ||||
-rw-r--r-- | arch/mips/kernel/smtc.c | 3 | ||||
-rw-r--r-- | arch/mips/kernel/sync-r4k.c | 159 | ||||
-rw-r--r-- | arch/mips/kernel/traps.c | 111 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/Makefile | 1 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/amon.c | 80 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/init.c | 3 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/time.c | 29 | ||||
-rw-r--r-- | arch/mips/mips-boards/malta/Makefile | 1 | ||||
-rw-r--r-- | arch/mips/mips-boards/malta/malta_int.c | 346 | ||||
-rw-r--r-- | arch/mips/mips-boards/malta/malta_setup.c | 6 | ||||
-rw-r--r-- | arch/mips/mm/c-r4k.c | 43 | ||||
-rw-r--r-- | arch/mips/mm/init.c | 2 | ||||
-rw-r--r-- | arch/mips/oprofile/common.c | 1 | ||||
-rw-r--r-- | arch/mips/oprofile/op_model_mipsxx.c | 34 |
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 | |||
840 | config MIPS_DISABLE_OBSOLETE_IDE | 841 | config MIPS_DISABLE_OBSOLETE_IDE |
841 | bool | 842 | bool |
842 | 843 | ||
844 | config SYNC_R4K | ||
845 | bool | ||
846 | |||
843 | config NO_IOPORT | 847 | config NO_IOPORT |
844 | def_bool n | 848 | def_bool n |
845 | 849 | ||
@@ -909,6 +913,9 @@ config IRQ_TXX9 | |||
909 | config IRQ_GT641XX | 913 | config IRQ_GT641XX |
910 | bool | 914 | bool |
911 | 915 | ||
916 | config IRQ_GIC | ||
917 | bool | ||
918 | |||
912 | config MIPS_BOARDS_GEN | 919 | config 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 | ||
1821 | config 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 | |||
1814 | source "kernel/time/Kconfig" | 1832 | source "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 | |||
16 | obj-$(CONFIG_CSRC_BCM1480) += csrc-bcm1480.o | 16 | obj-$(CONFIG_CSRC_BCM1480) += csrc-bcm1480.o |
17 | obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o | 17 | obj-$(CONFIG_CSRC_R4K) += csrc-r4k.o |
18 | obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o | 18 | obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o |
19 | obj-$(CONFIG_SYNC_R4K) += sync-r4k.o | ||
19 | 20 | ||
20 | binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \ | 21 | binfmt_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 | |||
50 | obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o | 51 | obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o |
51 | obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o | 52 | obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o |
52 | obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o | 53 | obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o |
54 | obj-$(CONFIG_MIPS_CMP) += smp-cmp.o | ||
53 | obj-$(CONFIG_CPU_MIPSR2) += spram.o | 55 | obj-$(CONFIG_CPU_MIPSR2) += spram.o |
54 | 56 | ||
55 | obj-$(CONFIG_MIPS_APSP_KSPD) += kspd.o | 57 | obj-$(CONFIG_MIPS_APSP_KSPD) += kspd.o |
@@ -63,6 +65,7 @@ obj-$(CONFIG_IRQ_CPU_RM9K) += irq-rm9000.o | |||
63 | obj-$(CONFIG_MIPS_BOARDS_GEN) += irq-msc01.o | 65 | obj-$(CONFIG_MIPS_BOARDS_GEN) += irq-msc01.o |
64 | obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o | 66 | obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o |
65 | obj-$(CONFIG_IRQ_GT641XX) += irq-gt641xx.o | 67 | obj-$(CONFIG_IRQ_GT641XX) += irq-gt641xx.o |
68 | obj-$(CONFIG_IRQ_GIC) += irq-gic.o | ||
66 | 69 | ||
67 | obj-$(CONFIG_32BIT) += scall32-o32.o | 70 | obj-$(CONFIG_32BIT) += scall32-o32.o |
68 | obj-$(CONFIG_64BIT) += scall64-64.o | 71 | obj-$(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 | |||
15 | static unsigned long _gic_base; | ||
16 | static unsigned int _irqbase, _mapsize, numvpes, numintrs; | ||
17 | static struct gic_intr_map *_intrmap; | ||
18 | |||
19 | static struct gic_pcpu_mask pcpu_masks[NR_CPUS]; | ||
20 | static struct gic_pending_regs pending_regs[NR_CPUS]; | ||
21 | static 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 | ||
27 | static DEFINE_SPINLOCK(gic_wedgeb2b_lock); | ||
28 | #endif | ||
29 | |||
30 | void 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 */ | ||
47 | static 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 | |||
72 | unsigned 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 | |||
105 | static 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 | |||
115 | static 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 | |||
136 | static 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 | |||
145 | static 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 | |||
156 | static DEFINE_SPINLOCK(gic_lock); | ||
157 | |||
158 | static 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 | |||
196 | static 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 | |||
209 | static 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 | |||
238 | static 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 | |||
271 | void __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 | */ | ||
47 | static 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 | |||
66 | static 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 | |||
91 | static 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 | */ | ||
119 | void 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 | |||
138 | static 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 | |||
146 | static void cmp_init_secondary(void) | ||
147 | { | ||
148 | struct cpuinfo_mips *c = ¤t_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 | |||
165 | static 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 | |||
181 | static 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 | */ | ||
192 | static 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 | */ | ||
214 | void __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 | |||
244 | void __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 | |||
256 | struct 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 | 39 | static void __init smvp_copy_vpe_config(void) |
40 | #define MIPS_CPU_IPI_CALL_IRQ 1 | ||
41 | |||
42 | static int cpu_ipi_resched_irq, cpu_ipi_call_irq; | ||
43 | |||
44 | #if 0 | ||
45 | static 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 | |||
61 | static void ipi_resched_dispatch(void) | ||
62 | { | ||
63 | do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ); | ||
64 | } | ||
65 | |||
66 | static void ipi_call_dispatch(void) | ||
67 | { | ||
68 | do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ); | ||
69 | } | ||
70 | |||
71 | static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) | ||
72 | { | ||
73 | return IRQ_HANDLED; | ||
74 | } | ||
75 | |||
76 | static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) | ||
77 | { | ||
78 | smp_call_function_interrupt(); | ||
79 | |||
80 | return IRQ_HANDLED; | ||
81 | } | ||
82 | |||
83 | static struct irqaction irq_resched = { | ||
84 | .handler = ipi_resched_interrupt, | ||
85 | .flags = IRQF_DISABLED|IRQF_PERCPU, | ||
86 | .name = "IPI_resched" | ||
87 | }; | ||
88 | |||
89 | static struct irqaction irq_call = { | ||
90 | .handler = ipi_call_interrupt, | ||
91 | .flags = IRQF_DISABLED|IRQF_PERCPU, | ||
92 | .name = "IPI_call" | ||
93 | }; | ||
94 | |||
95 | static 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 | ||
112 | static unsigned int __init smp_vpe_init(unsigned int tc, unsigned int mvpconf0, | 56 | static 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 | ||
143 | static void __init smp_tc_init(unsigned int tc, unsigned int mvpconf0) | 87 | static 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 | ||
208 | static void __cpuinit vsmp_init_secondary(void) | 152 | static 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 | ||
217 | static void __cpuinit vsmp_smp_finish(void) | 165 | static 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 | */ |
281 | static void __init vsmp_smp_setup(void) | 230 | static 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) | |||
324 | static void __init vsmp_prepare_cpus(unsigned int max_cpus) | 273 | static 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 | ||
344 | struct plat_smp_ops vsmp_smp_ops = { | 278 | struct 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) | |||
287 | void __init smp_cpus_done(unsigned int max_cpus) | 290 | void __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 | |||
23 | static atomic_t __initdata count_start_flag = ATOMIC_INIT(0); | ||
24 | static atomic_t __initdata count_count_start = ATOMIC_INIT(0); | ||
25 | static atomic_t __initdata count_count_stop = ATOMIC_INIT(0); | ||
26 | |||
27 | #define COUNTON 100 | ||
28 | #define NR_LOOPS 5 | ||
29 | |||
30 | void __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 | |||
109 | void __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 | ||
81 | static void show_raw_backtrace(unsigned long reg29) | 82 | static 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); | |||
192 | static void show_code(unsigned int __user *pc) | 196 | static 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 | ||
312 | void show_registers(const struct pt_regs *regs) | 319 | void 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 | ||
1006 | static int __initdata l1parity = 1; | ||
1007 | static int __init nol1parity(char *s) | ||
1008 | { | ||
1009 | l1parity = 0; | ||
1010 | return 1; | ||
1011 | } | ||
1012 | __setup("nol1par", nol1parity); | ||
1013 | static int __initdata l2parity = 1; | ||
1014 | static 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 | ||
21 | obj-y := reset.o display.o init.o memory.o \ | 21 | obj-y := reset.o display.o init.o memory.o \ |
22 | cmdline.o time.o | 22 | cmdline.o time.o |
23 | obj-y += amon.o | ||
23 | 24 | ||
24 | obj-$(CONFIG_EARLY_PRINTK) += console.o | 25 | obj-$(CONFIG_EARLY_PRINTK) += console.o |
25 | obj-$(CONFIG_PCI) += pci.o | 26 | obj-$(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 | |||
29 | int 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 | |||
51 | void 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 @@ | |||
55 | unsigned long cpu_khz; | 55 | unsigned long cpu_khz; |
56 | 56 | ||
57 | static int mips_cpu_timer_irq; | 57 | static int mips_cpu_timer_irq; |
58 | static int mips_cpu_perf_irq; | ||
58 | extern int cp0_perfcount_irq; | 59 | extern int cp0_perfcount_irq; |
59 | 60 | ||
61 | DEFINE_PER_CPU(unsigned int, tickcount); | ||
62 | #define tickcount_this_cpu __get_cpu_var(tickcount) | ||
63 | static unsigned long ledbitmask; | ||
64 | |||
60 | static void mips_timer_dispatch(void) | 65 | static 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 | ||
65 | static void mips_perf_dispatch(void) | 85 | static 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 | ||
130 | void __init plat_perf_setup(void) | 150 | void __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 @@ | |||
22 | obj-y := malta_int.o malta_platform.o malta_setup.o | 22 | obj-y := malta_int.o malta_platform.o malta_setup.o |
23 | 23 | ||
24 | obj-$(CONFIG_MTD) += malta_mtd.o | 24 | obj-$(CONFIG_MTD) += malta_mtd.o |
25 | # FIXME FIXME FIXME | ||
25 | obj-$(CONFIG_MIPS_MT_SMTC) += malta_smtc.o | 26 | obj-$(CONFIG_MIPS_MT_SMTC) += malta_smtc.o |
26 | 27 | ||
27 | EXTRA_CFLAGS += -Werror | 28 | EXTRA_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 | |||
48 | int gcmp_present = -1; | ||
49 | int gic_present; | ||
50 | static unsigned long _msc01_biu_base; | ||
51 | static unsigned long _gcmp_base; | ||
52 | static unsigned int ipi_map[NR_CPUS]; | ||
44 | 53 | ||
45 | static DEFINE_SPINLOCK(mips_irq_lock); | 54 | static 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 | ||
133 | static 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 | |||
124 | static void corehi_irqdispatch(void) | 144 | static 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 | ||
298 | static int cpu_ipi_resched_irq, cpu_ipi_call_irq; | ||
299 | |||
300 | static void ipi_resched_dispatch(void) | ||
301 | { | ||
302 | do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ); | ||
303 | } | ||
304 | |||
305 | static void ipi_call_dispatch(void) | ||
306 | { | ||
307 | do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ); | ||
308 | } | ||
309 | |||
310 | static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) | ||
311 | { | ||
312 | return IRQ_HANDLED; | ||
313 | } | ||
314 | |||
315 | static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) | ||
316 | { | ||
317 | smp_call_function_interrupt(); | ||
318 | |||
319 | return IRQ_HANDLED; | ||
320 | } | ||
321 | |||
322 | static struct irqaction irq_resched = { | ||
323 | .handler = ipi_resched_interrupt, | ||
324 | .flags = IRQF_DISABLED|IRQF_PERCPU, | ||
325 | .name = "IPI_resched" | ||
326 | }; | ||
327 | |||
328 | static 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 | |||
266 | static struct irqaction i8259irq = { | 335 | static 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 | |||
294 | int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap); | 364 | int __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 | */ | ||
371 | static 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 | */ | ||
401 | int __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 | |||
415 | void __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 | |||
296 | void __init arch_init_irq(void) | 426 | void __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 | |||
584 | void malta_be_init(void) | ||
585 | { | ||
586 | if (gcmp_present) { | ||
587 | /* Could change CM error mask register */ | ||
588 | } | ||
589 | } | ||
590 | |||
591 | |||
592 | static char *tr[8] = { | ||
593 | "mem", "gcr", "gic", "mmio", | ||
594 | "0x04", "0x05", "0x06", "0x07" | ||
595 | }; | ||
596 | |||
597 | static 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 | |||
632 | static 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 | |||
639 | static 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 | |||
650 | int 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 | ||
39 | extern void malta_be_init(void); | ||
40 | extern int malta_be_handler(struct pt_regs *regs, int is_fixup); | ||
41 | |||
39 | struct resource standard_io_resources[] = { | 42 | struct 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 | |||
1279 | static int __cpuinitdata coherentio; | ||
1280 | |||
1281 | static int __init setcoherentio(char *str) | ||
1282 | { | ||
1283 | coherentio = 1; | ||
1284 | |||
1285 | return 1; | ||
1286 | } | ||
1287 | |||
1288 | __setup("coherentio", setcoherentio); | ||
1289 | #endif | ||
1290 | |||
1268 | void __cpuinit r4k_cache_init(void) | 1291 | void __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())) | 35 | static 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 | ||
277 | static inline void reset_counters(int counters) | 280 | static 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 | } |