aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Cernekee <cernekee@gmail.com>2014-10-21 00:27:53 -0400
committerRalf Baechle <ralf@linux-mips.org>2014-11-24 01:45:10 -0500
commitfc4557879320de99766061a38aaa345c0f72eb31 (patch)
tree98d706c0374f1c7d198a096db4c0e3fda48859a4
parentbdb2e05c900d0c2a14605411dc054f284241d42e (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.c65
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
39static int __maybe_unused max_cpus = 1; 40static int __maybe_unused max_cpus = 1;
40 41
@@ -43,6 +44,9 @@ int bmips_smp_enabled = 1;
43int bmips_cpu_offset; 44int bmips_cpu_offset;
44cpumask_t bmips_booted_mask; 45cpumask_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
470struct reset_vec_info {
471 int cpu;
472 u32 val;
473};
474
475static 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
498static 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
466void bmips_ebase_setup(void) 522void 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;