diff options
Diffstat (limited to 'arch/mips/kernel/smp-bmips.c')
-rw-r--r-- | arch/mips/kernel/smp-bmips.c | 114 |
1 files changed, 73 insertions, 41 deletions
diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index 06bb5ed6d80a..b8bd9340c9c7 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <asm/bmips.h> | 35 | #include <asm/bmips.h> |
36 | #include <asm/traps.h> | 36 | #include <asm/traps.h> |
37 | #include <asm/barrier.h> | 37 | #include <asm/barrier.h> |
38 | #include <asm/cpu-features.h> | ||
38 | 39 | ||
39 | static int __maybe_unused max_cpus = 1; | 40 | static int __maybe_unused max_cpus = 1; |
40 | 41 | ||
@@ -42,6 +43,12 @@ static int __maybe_unused max_cpus = 1; | |||
42 | int bmips_smp_enabled = 1; | 43 | int bmips_smp_enabled = 1; |
43 | int bmips_cpu_offset; | 44 | int bmips_cpu_offset; |
44 | cpumask_t bmips_booted_mask; | 45 | cpumask_t bmips_booted_mask; |
46 | unsigned long bmips_tp1_irqs = IE_IRQ1; | ||
47 | |||
48 | #define RESET_FROM_KSEG0 0x80080800 | ||
49 | #define RESET_FROM_KSEG1 0xa0080800 | ||
50 | |||
51 | static void bmips_set_reset_vec(int cpu, u32 val); | ||
45 | 52 | ||
46 | #ifdef CONFIG_SMP | 53 | #ifdef CONFIG_SMP |
47 | 54 | ||
@@ -194,6 +201,9 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle) | |||
194 | pr_info("SMP: Booting CPU%d...\n", cpu); | 201 | pr_info("SMP: Booting CPU%d...\n", cpu); |
195 | 202 | ||
196 | if (cpumask_test_cpu(cpu, &bmips_booted_mask)) { | 203 | if (cpumask_test_cpu(cpu, &bmips_booted_mask)) { |
204 | /* kseg1 might not exist if this CPU enabled XKS01 */ | ||
205 | bmips_set_reset_vec(cpu, RESET_FROM_KSEG0); | ||
206 | |||
197 | switch (current_cpu_type()) { | 207 | switch (current_cpu_type()) { |
198 | case CPU_BMIPS4350: | 208 | case CPU_BMIPS4350: |
199 | case CPU_BMIPS4380: | 209 | case CPU_BMIPS4380: |
@@ -203,8 +213,9 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle) | |||
203 | bmips5000_send_ipi_single(cpu, 0); | 213 | bmips5000_send_ipi_single(cpu, 0); |
204 | break; | 214 | break; |
205 | } | 215 | } |
206 | } | 216 | } else { |
207 | else { | 217 | bmips_set_reset_vec(cpu, RESET_FROM_KSEG1); |
218 | |||
208 | switch (current_cpu_type()) { | 219 | switch (current_cpu_type()) { |
209 | case CPU_BMIPS4350: | 220 | case CPU_BMIPS4350: |
210 | case CPU_BMIPS4380: | 221 | case CPU_BMIPS4380: |
@@ -213,17 +224,7 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle) | |||
213 | set_c0_brcm_cmt_ctrl(0x01); | 224 | set_c0_brcm_cmt_ctrl(0x01); |
214 | break; | 225 | break; |
215 | case CPU_BMIPS5000: | 226 | case CPU_BMIPS5000: |
216 | if (cpu & 0x01) | 227 | write_c0_brcm_action(ACTION_BOOT_THREAD(cpu)); |
217 | write_c0_brcm_action(ACTION_BOOT_THREAD(cpu)); | ||
218 | else { | ||
219 | /* | ||
220 | * core N thread 0 was already booted; just | ||
221 | * pulse the NMI line | ||
222 | */ | ||
223 | bmips_write_zscm_reg(0x210, 0xc0000000); | ||
224 | udelay(10); | ||
225 | bmips_write_zscm_reg(0x210, 0x00); | ||
226 | } | ||
227 | break; | 228 | break; |
228 | } | 229 | } |
229 | cpumask_set_cpu(cpu, &bmips_booted_mask); | 230 | cpumask_set_cpu(cpu, &bmips_booted_mask); |
@@ -235,31 +236,12 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle) | |||
235 | */ | 236 | */ |
236 | static void bmips_init_secondary(void) | 237 | static void bmips_init_secondary(void) |
237 | { | 238 | { |
238 | /* move NMI vector to kseg0, in case XKS01 is enabled */ | ||
239 | |||
240 | void __iomem *cbr; | ||
241 | unsigned long old_vec; | ||
242 | unsigned long relo_vector; | ||
243 | int boot_cpu; | ||
244 | |||
245 | switch (current_cpu_type()) { | 239 | switch (current_cpu_type()) { |
246 | case CPU_BMIPS4350: | 240 | case CPU_BMIPS4350: |
247 | case CPU_BMIPS4380: | 241 | case CPU_BMIPS4380: |
248 | cbr = BMIPS_GET_CBR(); | ||
249 | |||
250 | boot_cpu = !!(read_c0_brcm_cmt_local() & (1 << 31)); | ||
251 | relo_vector = boot_cpu ? BMIPS_RELO_VECTOR_CONTROL_0 : | ||
252 | BMIPS_RELO_VECTOR_CONTROL_1; | ||
253 | |||
254 | old_vec = __raw_readl(cbr + relo_vector); | ||
255 | __raw_writel(old_vec & ~0x20000000, cbr + relo_vector); | ||
256 | |||
257 | clear_c0_cause(smp_processor_id() ? C_SW1 : C_SW0); | 242 | clear_c0_cause(smp_processor_id() ? C_SW1 : C_SW0); |
258 | break; | 243 | break; |
259 | case CPU_BMIPS5000: | 244 | case CPU_BMIPS5000: |
260 | write_c0_brcm_bootvec(read_c0_brcm_bootvec() & | ||
261 | (smp_processor_id() & 0x01 ? ~0x20000000 : ~0x2000)); | ||
262 | |||
263 | write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), 0)); | 245 | write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), 0)); |
264 | break; | 246 | break; |
265 | } | 247 | } |
@@ -276,7 +258,7 @@ static void bmips_smp_finish(void) | |||
276 | write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ); | 258 | write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ); |
277 | 259 | ||
278 | irq_enable_hazard(); | 260 | irq_enable_hazard(); |
279 | set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ1 | IE_IRQ5 | ST0_IE); | 261 | set_c0_status(IE_SW0 | IE_SW1 | bmips_tp1_irqs | IE_IRQ5 | ST0_IE); |
280 | irq_enable_hazard(); | 262 | irq_enable_hazard(); |
281 | } | 263 | } |
282 | 264 | ||
@@ -381,6 +363,7 @@ static int bmips_cpu_disable(void) | |||
381 | 363 | ||
382 | set_cpu_online(cpu, false); | 364 | set_cpu_online(cpu, false); |
383 | cpu_clear(cpu, cpu_callin_map); | 365 | cpu_clear(cpu, cpu_callin_map); |
366 | clear_c0_status(IE_IRQ5); | ||
384 | 367 | ||
385 | local_flush_tlb_all(); | 368 | local_flush_tlb_all(); |
386 | local_flush_icache_range(0, ~0); | 369 | local_flush_icache_range(0, ~0); |
@@ -405,7 +388,8 @@ void __ref play_dead(void) | |||
405 | * IRQ handlers; this clears ST0_IE and returns immediately. | 388 | * IRQ handlers; this clears ST0_IE and returns immediately. |
406 | */ | 389 | */ |
407 | clear_c0_cause(CAUSEF_IV | C_SW0 | C_SW1); | 390 | clear_c0_cause(CAUSEF_IV | C_SW0 | C_SW1); |
408 | change_c0_status(IE_IRQ5 | IE_IRQ1 | IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV, | 391 | change_c0_status( |
392 | IE_IRQ5 | bmips_tp1_irqs | IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV, | ||
409 | IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV); | 393 | IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV); |
410 | irq_disable_hazard(); | 394 | irq_disable_hazard(); |
411 | 395 | ||
@@ -473,10 +457,61 @@ static inline void bmips_nmi_handler_setup(void) | |||
473 | &bmips_smp_int_vec_end); | 457 | &bmips_smp_int_vec_end); |
474 | } | 458 | } |
475 | 459 | ||
460 | struct reset_vec_info { | ||
461 | int cpu; | ||
462 | u32 val; | ||
463 | }; | ||
464 | |||
465 | static void bmips_set_reset_vec_remote(void *vinfo) | ||
466 | { | ||
467 | struct reset_vec_info *info = vinfo; | ||
468 | int shift = info->cpu & 0x01 ? 16 : 0; | ||
469 | u32 mask = ~(0xffff << shift), val = info->val >> 16; | ||
470 | |||
471 | preempt_disable(); | ||
472 | if (smp_processor_id() > 0) { | ||
473 | smp_call_function_single(0, &bmips_set_reset_vec_remote, | ||
474 | info, 1); | ||
475 | } else { | ||
476 | if (info->cpu & 0x02) { | ||
477 | /* BMIPS5200 "should" use mask/shift, but it's buggy */ | ||
478 | bmips_write_zscm_reg(0xa0, (val << 16) | val); | ||
479 | bmips_read_zscm_reg(0xa0); | ||
480 | } else { | ||
481 | write_c0_brcm_bootvec((read_c0_brcm_bootvec() & mask) | | ||
482 | (val << shift)); | ||
483 | } | ||
484 | } | ||
485 | preempt_enable(); | ||
486 | } | ||
487 | |||
488 | static void bmips_set_reset_vec(int cpu, u32 val) | ||
489 | { | ||
490 | struct reset_vec_info info; | ||
491 | |||
492 | if (current_cpu_type() == CPU_BMIPS5000) { | ||
493 | /* this needs to run from CPU0 (which is always online) */ | ||
494 | info.cpu = cpu; | ||
495 | info.val = val; | ||
496 | bmips_set_reset_vec_remote(&info); | ||
497 | } else { | ||
498 | void __iomem *cbr = BMIPS_GET_CBR(); | ||
499 | |||
500 | if (cpu == 0) | ||
501 | __raw_writel(val, cbr + BMIPS_RELO_VECTOR_CONTROL_0); | ||
502 | else { | ||
503 | if (current_cpu_type() != CPU_BMIPS4380) | ||
504 | return; | ||
505 | __raw_writel(val, cbr + BMIPS_RELO_VECTOR_CONTROL_1); | ||
506 | } | ||
507 | } | ||
508 | __sync(); | ||
509 | back_to_back_c0_hazard(); | ||
510 | } | ||
511 | |||
476 | void bmips_ebase_setup(void) | 512 | void bmips_ebase_setup(void) |
477 | { | 513 | { |
478 | unsigned long new_ebase = ebase; | 514 | unsigned long new_ebase = ebase; |
479 | void __iomem __maybe_unused *cbr; | ||
480 | 515 | ||
481 | BUG_ON(ebase != CKSEG0); | 516 | BUG_ON(ebase != CKSEG0); |
482 | 517 | ||
@@ -496,15 +531,14 @@ void bmips_ebase_setup(void) | |||
496 | &bmips_smp_int_vec, 0x80); | 531 | &bmips_smp_int_vec, 0x80); |
497 | __sync(); | 532 | __sync(); |
498 | return; | 533 | return; |
534 | case CPU_BMIPS3300: | ||
499 | case CPU_BMIPS4380: | 535 | case CPU_BMIPS4380: |
500 | /* | 536 | /* |
501 | * 0x8000_0000: reset/NMI (initially in kseg1) | 537 | * 0x8000_0000: reset/NMI (initially in kseg1) |
502 | * 0x8000_0400: normal vectors | 538 | * 0x8000_0400: normal vectors |
503 | */ | 539 | */ |
504 | new_ebase = 0x80000400; | 540 | new_ebase = 0x80000400; |
505 | cbr = BMIPS_GET_CBR(); | 541 | bmips_set_reset_vec(0, RESET_FROM_KSEG0); |
506 | __raw_writel(0x80080800, cbr + BMIPS_RELO_VECTOR_CONTROL_0); | ||
507 | __raw_writel(0xa0080800, cbr + BMIPS_RELO_VECTOR_CONTROL_1); | ||
508 | break; | 542 | break; |
509 | case CPU_BMIPS5000: | 543 | case CPU_BMIPS5000: |
510 | /* | 544 | /* |
@@ -512,10 +546,8 @@ void bmips_ebase_setup(void) | |||
512 | * 0x8000_1000: normal vectors | 546 | * 0x8000_1000: normal vectors |
513 | */ | 547 | */ |
514 | new_ebase = 0x80001000; | 548 | new_ebase = 0x80001000; |
515 | write_c0_brcm_bootvec(0xa0088008); | 549 | bmips_set_reset_vec(0, RESET_FROM_KSEG0); |
516 | write_c0_ebase(new_ebase); | 550 | write_c0_ebase(new_ebase); |
517 | if (max_cpus > 2) | ||
518 | bmips_write_zscm_reg(0xa0, 0xa008a008); | ||
519 | break; | 551 | break; |
520 | default: | 552 | default: |
521 | return; | 553 | return; |