aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/mips-boards/malta
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/mips-boards/malta')
-rw-r--r--arch/mips/mips-boards/malta/Makefile1
-rw-r--r--arch/mips/mips-boards/malta/malta_int.c105
-rw-r--r--arch/mips/mips-boards/malta/malta_smp.c128
3 files changed, 228 insertions, 6 deletions
diff --git a/arch/mips/mips-boards/malta/Makefile b/arch/mips/mips-boards/malta/Makefile
index fd4c143c0e2f..77ee5c6d33c1 100644
--- a/arch/mips/mips-boards/malta/Makefile
+++ b/arch/mips/mips-boards/malta/Makefile
@@ -20,3 +20,4 @@
20# 20#
21 21
22obj-y := malta_int.o malta_setup.o 22obj-y := malta_int.o malta_setup.o
23obj-$(CONFIG_SMP) += malta_smp.o
diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c
index d06dc5ad6c9e..7cc0ba4f553a 100644
--- a/arch/mips/mips-boards/malta/malta_int.c
+++ b/arch/mips/mips-boards/malta/malta_int.c
@@ -40,7 +40,6 @@
40#include <asm/mips-boards/msc01_pci.h> 40#include <asm/mips-boards/msc01_pci.h>
41#include <asm/msc01_ic.h> 41#include <asm/msc01_ic.h>
42 42
43extern asmlinkage void mipsIRQ(void);
44extern void mips_timer_interrupt(void); 43extern void mips_timer_interrupt(void);
45 44
46static DEFINE_SPINLOCK(mips_irq_lock); 45static DEFINE_SPINLOCK(mips_irq_lock);
@@ -58,6 +57,7 @@ static inline int mips_pcibios_iack(void)
58 case MIPS_REVISION_CORID_CORE_MSC: 57 case MIPS_REVISION_CORID_CORE_MSC:
59 case MIPS_REVISION_CORID_CORE_FPGA2: 58 case MIPS_REVISION_CORID_CORE_FPGA2:
60 case MIPS_REVISION_CORID_CORE_FPGA3: 59 case MIPS_REVISION_CORID_CORE_FPGA3:
60 case MIPS_REVISION_CORID_CORE_24K:
61 case MIPS_REVISION_CORID_CORE_EMUL_MSC: 61 case MIPS_REVISION_CORID_CORE_EMUL_MSC:
62 MSC_READ(MSC01_PCI_IACK, irq); 62 MSC_READ(MSC01_PCI_IACK, irq);
63 irq &= 0xff; 63 irq &= 0xff;
@@ -114,13 +114,14 @@ static inline int get_int(void)
114 return irq; 114 return irq;
115} 115}
116 116
117void malta_hw0_irqdispatch(struct pt_regs *regs) 117static void malta_hw0_irqdispatch(struct pt_regs *regs)
118{ 118{
119 int irq; 119 int irq;
120 120
121 irq = get_int(); 121 irq = get_int();
122 if (irq < 0) 122 if (irq < 0) {
123 return; /* interrupt has already been cleared */ 123 return; /* interrupt has already been cleared */
124 }
124 125
125 do_IRQ(MALTA_INT_BASE+irq, regs); 126 do_IRQ(MALTA_INT_BASE+irq, regs);
126} 127}
@@ -143,6 +144,7 @@ void corehi_irqdispatch(struct pt_regs *regs)
143 case MIPS_REVISION_CORID_CORE_MSC: 144 case MIPS_REVISION_CORID_CORE_MSC:
144 case MIPS_REVISION_CORID_CORE_FPGA2: 145 case MIPS_REVISION_CORID_CORE_FPGA2:
145 case MIPS_REVISION_CORID_CORE_FPGA3: 146 case MIPS_REVISION_CORID_CORE_FPGA3:
147 case MIPS_REVISION_CORID_CORE_24K:
146 case MIPS_REVISION_CORID_CORE_EMUL_MSC: 148 case MIPS_REVISION_CORID_CORE_EMUL_MSC:
147 ll_msc_irq(regs); 149 ll_msc_irq(regs);
148 break; 150 break;
@@ -182,6 +184,92 @@ void corehi_irqdispatch(struct pt_regs *regs)
182 die("CoreHi interrupt", regs); 184 die("CoreHi interrupt", regs);
183} 185}
184 186
187static inline int clz(unsigned long x)
188{
189 __asm__ (
190 " .set push \n"
191 " .set mips32 \n"
192 " clz %0, %1 \n"
193 " .set pop \n"
194 : "=r" (x)
195 : "r" (x));
196
197 return x;
198}
199
200/*
201 * Version of ffs that only looks at bits 12..15.
202 */
203static inline unsigned int irq_ffs(unsigned int pending)
204{
205#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
206 return -clz(pending) + 31 - CAUSEB_IP;
207#else
208 unsigned int a0 = 7;
209 unsigned int t0;
210
211 t0 = s0 & 0xf000;
212 t0 = t0 < 1;
213 t0 = t0 << 2;
214 a0 = a0 - t0;
215 s0 = s0 << t0;
216
217 t0 = s0 & 0xc000;
218 t0 = t0 < 1;
219 t0 = t0 << 1;
220 a0 = a0 - t0;
221 s0 = s0 << t0;
222
223 t0 = s0 & 0x8000;
224 t0 = t0 < 1;
225 //t0 = t0 << 2;
226 a0 = a0 - t0;
227 //s0 = s0 << t0;
228
229 return a0;
230#endif
231}
232
233/*
234 * IRQs on the Malta board look basically (barring software IRQs which we
235 * don't use at all and all external interrupt sources are combined together
236 * on hardware interrupt 0 (MIPS IRQ 2)) like:
237 *
238 * MIPS IRQ Source
239 * -------- ------
240 * 0 Software (ignored)
241 * 1 Software (ignored)
242 * 2 Combined hardware interrupt (hw0)
243 * 3 Hardware (ignored)
244 * 4 Hardware (ignored)
245 * 5 Hardware (ignored)
246 * 6 Hardware (ignored)
247 * 7 R4k timer (what we use)
248 *
249 * We handle the IRQ according to _our_ priority which is:
250 *
251 * Highest ---- R4k Timer
252 * Lowest ---- Combined hardware interrupt
253 *
254 * then we just return, if multiple IRQs are pending then we will just take
255 * another exception, big deal.
256 */
257
258asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
259{
260 unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
261 int irq;
262
263 irq = irq_ffs(pending);
264
265 if (irq == MIPSCPU_INT_I8259A)
266 malta_hw0_irqdispatch(regs);
267 else if (irq > 0)
268 do_IRQ(MIPSCPU_INT_BASE + irq, regs);
269 else
270 spurious_interrupt(regs);
271}
272
185static struct irqaction i8259irq = { 273static struct irqaction i8259irq = {
186 .handler = no_action, 274 .handler = no_action,
187 .name = "XT-PIC cascade" 275 .name = "XT-PIC cascade"
@@ -214,7 +302,6 @@ int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap)/sizeof(msc_irqmap_t);
214 302
215void __init arch_init_irq(void) 303void __init arch_init_irq(void)
216{ 304{
217 set_except_vector(0, mipsIRQ);
218 init_i8259_irqs(); 305 init_i8259_irqs();
219 306
220 if (!cpu_has_veic) 307 if (!cpu_has_veic)
@@ -224,6 +311,7 @@ void __init arch_init_irq(void)
224 case MIPS_REVISION_CORID_CORE_MSC: 311 case MIPS_REVISION_CORID_CORE_MSC:
225 case MIPS_REVISION_CORID_CORE_FPGA2: 312 case MIPS_REVISION_CORID_CORE_FPGA2:
226 case MIPS_REVISION_CORID_CORE_FPGA3: 313 case MIPS_REVISION_CORID_CORE_FPGA3:
314 case MIPS_REVISION_CORID_CORE_24K:
227 case MIPS_REVISION_CORID_CORE_EMUL_MSC: 315 case MIPS_REVISION_CORID_CORE_EMUL_MSC:
228 if (cpu_has_veic) 316 if (cpu_has_veic)
229 init_msc_irqs (MSC01E_INT_BASE, msc_eicirqmap, msc_nr_eicirqs); 317 init_msc_irqs (MSC01E_INT_BASE, msc_eicirqmap, msc_nr_eicirqs);
@@ -240,12 +328,17 @@ void __init arch_init_irq(void)
240 else if (cpu_has_vint) { 328 else if (cpu_has_vint) {
241 set_vi_handler (MIPSCPU_INT_I8259A, malta_hw0_irqdispatch); 329 set_vi_handler (MIPSCPU_INT_I8259A, malta_hw0_irqdispatch);
242 set_vi_handler (MIPSCPU_INT_COREHI, corehi_irqdispatch); 330 set_vi_handler (MIPSCPU_INT_COREHI, corehi_irqdispatch);
243 331#ifdef CONFIG_MIPS_MT_SMTC
332 setup_irq_smtc (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq,
333 (0x100 << MIPSCPU_INT_I8259A));
334 setup_irq_smtc (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI,
335 &corehi_irqaction, (0x100 << MIPSCPU_INT_COREHI));
336#else /* Not SMTC */
244 setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq); 337 setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq);
245 setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction); 338 setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction);
339#endif /* CONFIG_MIPS_MT_SMTC */
246 } 340 }
247 else { 341 else {
248 set_except_vector(0, mipsIRQ);
249 setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq); 342 setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq);
250 setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction); 343 setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction);
251 } 344 }
diff --git a/arch/mips/mips-boards/malta/malta_smp.c b/arch/mips/mips-boards/malta/malta_smp.c
new file mode 100644
index 000000000000..6c6c8eeedbce
--- /dev/null
+++ b/arch/mips/mips-boards/malta/malta_smp.c
@@ -0,0 +1,128 @@
1/*
2 * Malta Platform-specific hooks for SMP operation
3 */
4
5#include <linux/kernel.h>
6#include <linux/sched.h>
7#include <linux/cpumask.h>
8#include <linux/interrupt.h>
9
10#include <asm/atomic.h>
11#include <asm/cpu.h>
12#include <asm/processor.h>
13#include <asm/system.h>
14#include <asm/hardirq.h>
15#include <asm/mmu_context.h>
16#include <asm/smp.h>
17#ifdef CONFIG_MIPS_MT_SMTC
18#include <asm/smtc_ipi.h>
19#endif /* CONFIG_MIPS_MT_SMTC */
20
21/* VPE/SMP Prototype implements platform interfaces directly */
22#if !defined(CONFIG_MIPS_MT_SMP)
23
24/*
25 * Cause the specified action to be performed on a targeted "CPU"
26 */
27
28void core_send_ipi(int cpu, unsigned int action)
29{
30/* "CPU" may be TC of same VPE, VPE of same CPU, or different CPU */
31#ifdef CONFIG_MIPS_MT_SMTC
32 smtc_send_ipi(cpu, LINUX_SMP_IPI, action);
33#endif /* CONFIG_MIPS_MT_SMTC */
34}
35
36/*
37 * Detect available CPUs/VPEs/TCs and populate phys_cpu_present_map
38 */
39
40void __init prom_build_cpu_map(void)
41{
42 int nextslot;
43
44 /*
45 * As of November, 2004, MIPSsim only simulates one core
46 * at a time. However, that core may be a MIPS MT core
47 * with multiple virtual processors and thread contexts.
48 */
49
50 if (read_c0_config3() & (1<<2)) {
51 nextslot = mipsmt_build_cpu_map(1);
52 }
53}
54
55/*
56 * Platform "CPU" startup hook
57 */
58
59void prom_boot_secondary(int cpu, struct task_struct *idle)
60{
61#ifdef CONFIG_MIPS_MT_SMTC
62 smtc_boot_secondary(cpu, idle);
63#endif /* CONFIG_MIPS_MT_SMTC */
64}
65
66/*
67 * Post-config but pre-boot cleanup entry point
68 */
69
70void prom_init_secondary(void)
71{
72#ifdef CONFIG_MIPS_MT_SMTC
73 void smtc_init_secondary(void);
74 int myvpe;
75
76 /* Don't enable Malta I/O interrupts (IP2) for secondary VPEs */
77 myvpe = read_c0_tcbind() & TCBIND_CURVPE;
78 if (myvpe != 0) {
79 /* Ideally, this should be done only once per VPE, but... */
80 clear_c0_status(STATUSF_IP2);
81 set_c0_status(STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP3
82 | STATUSF_IP4 | STATUSF_IP5 | STATUSF_IP6
83 | STATUSF_IP7);
84 }
85
86 smtc_init_secondary();
87#endif /* CONFIG_MIPS_MT_SMTC */
88}
89
90/*
91 * Platform SMP pre-initialization
92 *
93 * As noted above, we can assume a single CPU for now
94 * but it may be multithreaded.
95 */
96
97void plat_smp_setup(void)
98{
99 if (read_c0_config3() & (1<<2))
100 mipsmt_build_cpu_map(0);
101}
102
103void __init plat_prepare_cpus(unsigned int max_cpus)
104{
105 if (read_c0_config3() & (1<<2))
106 mipsmt_prepare_cpus();
107}
108
109/*
110 * SMP initialization finalization entry point
111 */
112
113void prom_smp_finish(void)
114{
115#ifdef CONFIG_MIPS_MT_SMTC
116 smtc_smp_finish();
117#endif /* CONFIG_MIPS_MT_SMTC */
118}
119
120/*
121 * Hook for after all CPUs are online
122 */
123
124void prom_cpus_done(void)
125{
126}
127
128#endif /* CONFIG_MIPS32R2_MT_SMP */