diff options
author | Kevin Cernekee <cernekee@gmail.com> | 2014-10-21 00:27:53 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2014-11-24 01:45:10 -0500 |
commit | fc4557879320de99766061a38aaa345c0f72eb31 (patch) | |
tree | 98d706c0374f1c7d198a096db4c0e3fda48859a4 | |
parent | bdb2e05c900d0c2a14605411dc054f284241d42e (diff) |
MIPS: BMIPS: Introduce helper function to change the reset vector
This will need to be called from a few different places, and the logic
is starting to get a bit hairy (with the need for IPIs, CPU bug
workarounds, and hazards).
Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
Cc: f.fainelli@gmail.com
Cc: mbizon@freebox.fr
Cc: jogo@openwrt.org
Cc: jfraser@broadcom.com
Cc: linux-mips@linux-mips.org
Cc: devicetree@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/8158/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r-- | arch/mips/kernel/smp-bmips.c | 65 |
1 files changed, 58 insertions, 7 deletions
diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index 4e569113ff56..8383fa460d42 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 | ||
@@ -43,6 +44,9 @@ 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; |
45 | 46 | ||
47 | #define RESET_FROM_KSEG0 0x80080800 | ||
48 | #define RESET_FROM_KSEG1 0xa0080800 | ||
49 | |||
46 | #ifdef CONFIG_SMP | 50 | #ifdef CONFIG_SMP |
47 | 51 | ||
48 | /* initial $sp, $gp - used by arch/mips/kernel/bmips_vec.S */ | 52 | /* initial $sp, $gp - used by arch/mips/kernel/bmips_vec.S */ |
@@ -463,10 +467,61 @@ static inline void bmips_nmi_handler_setup(void) | |||
463 | &bmips_smp_int_vec_end); | 467 | &bmips_smp_int_vec_end); |
464 | } | 468 | } |
465 | 469 | ||
470 | struct reset_vec_info { | ||
471 | int cpu; | ||
472 | u32 val; | ||
473 | }; | ||
474 | |||
475 | static void bmips_set_reset_vec_remote(void *vinfo) | ||
476 | { | ||
477 | struct reset_vec_info *info = vinfo; | ||
478 | int shift = info->cpu & 0x01 ? 16 : 0; | ||
479 | u32 mask = ~(0xffff << shift), val = info->val >> 16; | ||
480 | |||
481 | preempt_disable(); | ||
482 | if (smp_processor_id() > 0) { | ||
483 | smp_call_function_single(0, &bmips_set_reset_vec_remote, | ||
484 | info, 1); | ||
485 | } else { | ||
486 | if (info->cpu & 0x02) { | ||
487 | /* BMIPS5200 "should" use mask/shift, but it's buggy */ | ||
488 | bmips_write_zscm_reg(0xa0, (val << 16) | val); | ||
489 | bmips_read_zscm_reg(0xa0); | ||
490 | } else { | ||
491 | write_c0_brcm_bootvec((read_c0_brcm_bootvec() & mask) | | ||
492 | (val << shift)); | ||
493 | } | ||
494 | } | ||
495 | preempt_enable(); | ||
496 | } | ||
497 | |||
498 | static void bmips_set_reset_vec(int cpu, u32 val) | ||
499 | { | ||
500 | struct reset_vec_info info; | ||
501 | |||
502 | if (current_cpu_type() == CPU_BMIPS5000) { | ||
503 | /* this needs to run from CPU0 (which is always online) */ | ||
504 | info.cpu = cpu; | ||
505 | info.val = val; | ||
506 | bmips_set_reset_vec_remote(&info); | ||
507 | } else { | ||
508 | void __iomem *cbr = BMIPS_GET_CBR(); | ||
509 | |||
510 | if (cpu == 0) | ||
511 | __raw_writel(val, cbr + BMIPS_RELO_VECTOR_CONTROL_0); | ||
512 | else { | ||
513 | if (current_cpu_type() != CPU_BMIPS4380) | ||
514 | return; | ||
515 | __raw_writel(val, cbr + BMIPS_RELO_VECTOR_CONTROL_1); | ||
516 | } | ||
517 | } | ||
518 | __sync(); | ||
519 | back_to_back_c0_hazard(); | ||
520 | } | ||
521 | |||
466 | void bmips_ebase_setup(void) | 522 | void bmips_ebase_setup(void) |
467 | { | 523 | { |
468 | unsigned long new_ebase = ebase; | 524 | unsigned long new_ebase = ebase; |
469 | void __iomem __maybe_unused *cbr; | ||
470 | 525 | ||
471 | BUG_ON(ebase != CKSEG0); | 526 | BUG_ON(ebase != CKSEG0); |
472 | 527 | ||
@@ -492,9 +547,7 @@ void bmips_ebase_setup(void) | |||
492 | * 0x8000_0400: normal vectors | 547 | * 0x8000_0400: normal vectors |
493 | */ | 548 | */ |
494 | new_ebase = 0x80000400; | 549 | new_ebase = 0x80000400; |
495 | cbr = BMIPS_GET_CBR(); | 550 | bmips_set_reset_vec(0, RESET_FROM_KSEG0); |
496 | __raw_writel(0x80080800, cbr + BMIPS_RELO_VECTOR_CONTROL_0); | ||
497 | __raw_writel(0xa0080800, cbr + BMIPS_RELO_VECTOR_CONTROL_1); | ||
498 | break; | 551 | break; |
499 | case CPU_BMIPS5000: | 552 | case CPU_BMIPS5000: |
500 | /* | 553 | /* |
@@ -502,10 +555,8 @@ void bmips_ebase_setup(void) | |||
502 | * 0x8000_1000: normal vectors | 555 | * 0x8000_1000: normal vectors |
503 | */ | 556 | */ |
504 | new_ebase = 0x80001000; | 557 | new_ebase = 0x80001000; |
505 | write_c0_brcm_bootvec(0xa0088008); | 558 | bmips_set_reset_vec(0, RESET_FROM_KSEG0); |
506 | write_c0_ebase(new_ebase); | 559 | write_c0_ebase(new_ebase); |
507 | if (max_cpus > 2) | ||
508 | bmips_write_zscm_reg(0xa0, 0xa008a008); | ||
509 | break; | 560 | break; |
510 | default: | 561 | default: |
511 | return; | 562 | return; |