diff options
Diffstat (limited to 'arch/mips/mips-boards/malta')
-rw-r--r-- | arch/mips/mips-boards/malta/Makefile | 1 | ||||
-rw-r--r-- | arch/mips/mips-boards/malta/malta_int.c | 105 | ||||
-rw-r--r-- | arch/mips/mips-boards/malta/malta_smp.c | 128 |
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 | ||
22 | obj-y := malta_int.o malta_setup.o | 22 | obj-y := malta_int.o malta_setup.o |
23 | obj-$(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 | ||
43 | extern asmlinkage void mipsIRQ(void); | ||
44 | extern void mips_timer_interrupt(void); | 43 | extern void mips_timer_interrupt(void); |
45 | 44 | ||
46 | static DEFINE_SPINLOCK(mips_irq_lock); | 45 | static 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 | ||
117 | void malta_hw0_irqdispatch(struct pt_regs *regs) | 117 | static 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 | ||
187 | static 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 | */ | ||
203 | static 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 | |||
258 | asmlinkage 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 | |||
185 | static struct irqaction i8259irq = { | 273 | static 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 | ||
215 | void __init arch_init_irq(void) | 303 | void __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 | |||
28 | void 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 | |||
40 | void __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 | |||
59 | void 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 | |||
70 | void 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 | |||
97 | void plat_smp_setup(void) | ||
98 | { | ||
99 | if (read_c0_config3() & (1<<2)) | ||
100 | mipsmt_build_cpu_map(0); | ||
101 | } | ||
102 | |||
103 | void __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 | |||
113 | void 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 | |||
124 | void prom_cpus_done(void) | ||
125 | { | ||
126 | } | ||
127 | |||
128 | #endif /* CONFIG_MIPS32R2_MT_SMP */ | ||