[U-Boot] [PATCH] MIPS: Hang if run on a secondary CPU

Some systems are configured such that multiple CPUs begin running from their reset vector following a system reset. If this occurs then U-Boot will be run on multiple CPUs simultaneously, which causes all sorts of issues as the multiple instances of U-Boot clobber each other.
Prevent this from happening by simply hanging with an infinite loop if we run on a CPU whose ID, as determined by GlobalNumber or EBase.CPUNum as appropriate, is non-zero.
Signed-off-by: Paul Burton paul.burton@imgtec.com ---
arch/mips/cpu/start.S | 25 +++++++++++++++++++++++++ arch/mips/include/asm/mipsregs.h | 7 +++++++ 2 files changed, 32 insertions(+)
diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S index fc6dd66..dd37ac3 100644 --- a/arch/mips/cpu/start.S +++ b/arch/mips/cpu/start.S @@ -112,6 +112,31 @@ ENTRY(_start)
.align 4 reset: +#if __mips_isa_rev >= 6 + .set push + .set reorder + mfc0 t0, CP0_CONFIG, 1 + bgez t0, 1f + mfc0 t0, CP0_CONFIG, 2 + bgez t0, 1f + mfc0 t0, CP0_CONFIG, 3 + bgez t0, 1f + mfc0 t0, CP0_CONFIG, 4 + bgez t0, 1f + mfc0 t0, CP0_CONFIG, 5 + and t0, t0, MIPS_CONF5_VP + beqz t0, 1f + + mfc0 t0, CP0_GLOBALNUMBER + b 2f + .set pop +#endif + +1: mfc0 t0, CP0_EBASE + and t0, t0, EBASE_CPUNUM + + /* Hang if this isn't the first CPU in the system */ +2: bnez t0, .
/* Clear watch registers */ MTC0 zero, CP0_WATCHLO diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 3185dc7..9a4c4c5 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -39,6 +39,7 @@ #define CP0_ENTRYLO0 $2 #define CP0_ENTRYLO1 $3 #define CP0_CONF $3 +#define CP0_GLOBALNUMBER $3, 1 #define CP0_CONTEXT $4 #define CP0_PAGEMASK $5 #define CP0_WIRED $6 @@ -361,6 +362,11 @@ #define CAUSEF_BD (_ULCAST_(1) << 31)
/* + * Bits in the coprocessor 0 EBase register. + */ +#define EBASE_CPUNUM 0x3ff + +/* * Bits in the coprocessor 0 config register. */ /* Generic bits. */ @@ -548,6 +554,7 @@ #define MIPS_CONF5_MRP (_ULCAST_(1) << 3) #define MIPS_CONF5_LLB (_ULCAST_(1) << 4) #define MIPS_CONF5_MVH (_ULCAST_(1) << 5) +#define MIPS_CONF5_VP (_ULCAST_(1) << 7) #define MIPS_CONF5_FRE (_ULCAST_(1) << 8) #define MIPS_CONF5_UFE (_ULCAST_(1) << 9) #define MIPS_CONF5_MSAEN (_ULCAST_(1) << 27)

Hello Paul,
diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S index fc6dd66..dd37ac3 100644 --- a/arch/mips/cpu/start.S +++ b/arch/mips/cpu/start.S @@ -112,6 +112,31 @@ ENTRY(_start)
.align 4 reset: +#if __mips_isa_rev >= 6
- .set push
- .set reorder
- mfc0 t0, CP0_CONFIG, 1
- bgez t0, 1f
- mfc0 t0, CP0_CONFIG, 2
- bgez t0, 1f
- mfc0 t0, CP0_CONFIG, 3
- bgez t0, 1f
- mfc0 t0, CP0_CONFIG, 4
- bgez t0, 1f
- mfc0 t0, CP0_CONFIG, 5
- and t0, t0, MIPS_CONF5_VP
- beqz t0, 1f
- mfc0 t0, CP0_GLOBALNUMBER
- b 2f
- .set pop
+#endif
+1: mfc0 t0, CP0_EBASE
- and t0, t0, EBASE_CPUNUM
- /* Hang if this isn't the first CPU in the system */
+2: bnez t0, .
This loop should include a "wait" instruction. Otherwise the CPU will burn power for doing nothing.
Thomas

On Wednesday, 21 September 2016 12:59:39 BST Langer, Thomas wrote:
Hello Paul,
diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S index fc6dd66..dd37ac3 100644 --- a/arch/mips/cpu/start.S +++ b/arch/mips/cpu/start.S @@ -112,6 +112,31 @@ ENTRY(_start)
.align 4
reset: +#if __mips_isa_rev >= 6
- .set push
- .set reorder
- mfc0 t0, CP0_CONFIG, 1
- bgez t0, 1f
- mfc0 t0, CP0_CONFIG, 2
- bgez t0, 1f
- mfc0 t0, CP0_CONFIG, 3
- bgez t0, 1f
- mfc0 t0, CP0_CONFIG, 4
- bgez t0, 1f
- mfc0 t0, CP0_CONFIG, 5
- and t0, t0, MIPS_CONF5_VP
- beqz t0, 1f
- mfc0 t0, CP0_GLOBALNUMBER
- b 2f
- .set pop
+#endif
+1: mfc0 t0, CP0_EBASE
- and t0, t0, EBASE_CPUNUM
- /* Hang if this isn't the first CPU in the system */
+2: bnez t0, .
This loop should include a "wait" instruction. Otherwise the CPU will burn power for doing nothing.
Thomas
Hi Thomas,
True, it would spin until (typically) it gets reset by Linux or whatever OS is booted. I'll add a wait.
Thanks, Paul

Hi Paul,
Am 21.09.2016 um 12:08 schrieb Paul Burton:
Some systems are configured such that multiple CPUs begin running from their reset vector following a system reset. If this occurs then U-Boot will be run on multiple CPUs simultaneously, which causes all sorts of issues as the multiple instances of U-Boot clobber each other.
Prevent this from happening by simply hanging with an infinite loop if we run on a CPU whose ID, as determined by GlobalNumber or EBase.CPUNum as appropriate, is non-zero.
Signed-off-by: Paul Burton paul.burton@imgtec.com
just a tipp: please try to use patman with -m to disable automatic generation of the CC list and configure the CC addresses manually in the patches. Your CC list is always bigger than needed. I doubt that most of the guys care about MIPS low-level stuff ;)
Also please rebase this and your other patch on top of u-boot-mips/next. I'm getting conflicts when applying. Thanks.
arch/mips/cpu/start.S | 25 +++++++++++++++++++++++++ arch/mips/include/asm/mipsregs.h | 7 +++++++ 2 files changed, 32 insertions(+)
diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S index fc6dd66..dd37ac3 100644 --- a/arch/mips/cpu/start.S +++ b/arch/mips/cpu/start.S @@ -112,6 +112,31 @@ ENTRY(_start)
.align 4 reset: +#if __mips_isa_rev >= 6
- .set push
- .set reorder
- mfc0 t0, CP0_CONFIG, 1
- bgez t0, 1f
- mfc0 t0, CP0_CONFIG, 2
- bgez t0, 1f
- mfc0 t0, CP0_CONFIG, 3
- bgez t0, 1f
- mfc0 t0, CP0_CONFIG, 4
- bgez t0, 1f
- mfc0 t0, CP0_CONFIG, 5
- and t0, t0, MIPS_CONF5_VP
- beqz t0, 1f
- mfc0 t0, CP0_GLOBALNUMBER
- b 2f
- .set pop
+#endif
+1: mfc0 t0, CP0_EBASE
- and t0, t0, EBASE_CPUNUM
- /* Hang if this isn't the first CPU in the system */
+2: bnez t0, .
What about the branch delay slot? start.S is globally set to .noreorder and this particular branch instruction is also used for MIPS < r6
/* Clear watch registers */ MTC0 zero, CP0_WATCHLO diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 3185dc7..9a4c4c5 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -39,6 +39,7 @@ #define CP0_ENTRYLO0 $2 #define CP0_ENTRYLO1 $3 #define CP0_CONF $3 +#define CP0_GLOBALNUMBER $3, 1 #define CP0_CONTEXT $4 #define CP0_PAGEMASK $5 #define CP0_WIRED $6 @@ -361,6 +362,11 @@ #define CAUSEF_BD (_ULCAST_(1) << 31)
/*
- Bits in the coprocessor 0 EBase register.
- */
+#define EBASE_CPUNUM 0x3ff
+/*
- Bits in the coprocessor 0 config register.
*/ /* Generic bits. */ @@ -548,6 +554,7 @@ #define MIPS_CONF5_MRP (_ULCAST_(1) << 3) #define MIPS_CONF5_LLB (_ULCAST_(1) << 4) #define MIPS_CONF5_MVH (_ULCAST_(1) << 5) +#define MIPS_CONF5_VP (_ULCAST_(1) << 7) #define MIPS_CONF5_FRE (_ULCAST_(1) << 8) #define MIPS_CONF5_UFE (_ULCAST_(1) << 9) #define MIPS_CONF5_MSAEN (_ULCAST_(1) << 27)

On Wednesday, 21 September 2016 15:14:41 BST Daniel Schwierzeck wrote:
Hi Paul,
Am 21.09.2016 um 12:08 schrieb Paul Burton:
Some systems are configured such that multiple CPUs begin running from their reset vector following a system reset. If this occurs then U-Boot will be run on multiple CPUs simultaneously, which causes all sorts of issues as the multiple instances of U-Boot clobber each other.
Prevent this from happening by simply hanging with an infinite loop if we run on a CPU whose ID, as determined by GlobalNumber or EBase.CPUNum as appropriate, is non-zero.
Signed-off-by: Paul Burton paul.burton@imgtec.com
just a tipp: please try to use patman with -m to disable automatic generation of the CC list and configure the CC addresses manually in the patches. Your CC list is always bigger than needed. I doubt that most of the guys care about MIPS low-level stuff ;)
Hi Daniel,
OK, happy to do that.
Also please rebase this and your other patch on top of u-boot-mips/next. I'm getting conflicts when applying. Thanks.
I've just submitted a v2 of this patch which is based atop u-boot-mips/next. Which other patch were you seeing conflicts with?
Thanks for merging the L2 code.
Thanks, Paul
arch/mips/cpu/start.S | 25 +++++++++++++++++++++++++ arch/mips/include/asm/mipsregs.h | 7 +++++++ 2 files changed, 32 insertions(+)
diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S index fc6dd66..dd37ac3 100644 --- a/arch/mips/cpu/start.S +++ b/arch/mips/cpu/start.S @@ -112,6 +112,31 @@ ENTRY(_start)
.align 4
reset: +#if __mips_isa_rev >= 6
- .set push
- .set reorder
- mfc0 t0, CP0_CONFIG, 1
- bgez t0, 1f
- mfc0 t0, CP0_CONFIG, 2
- bgez t0, 1f
- mfc0 t0, CP0_CONFIG, 3
- bgez t0, 1f
- mfc0 t0, CP0_CONFIG, 4
- bgez t0, 1f
- mfc0 t0, CP0_CONFIG, 5
- and t0, t0, MIPS_CONF5_VP
- beqz t0, 1f
- mfc0 t0, CP0_GLOBALNUMBER
- b 2f
- .set pop
+#endif
+1: mfc0 t0, CP0_EBASE
- and t0, t0, EBASE_CPUNUM
- /* Hang if this isn't the first CPU in the system */
+2: bnez t0, .
What about the branch delay slot? start.S is globally set to .noreorder and this particular branch instruction is also used for MIPS < r6
/* Clear watch registers */ MTC0 zero, CP0_WATCHLO
diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 3185dc7..9a4c4c5 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -39,6 +39,7 @@
#define CP0_ENTRYLO0 $2 #define CP0_ENTRYLO1 $3 #define CP0_CONF $3
+#define CP0_GLOBALNUMBER $3, 1
#define CP0_CONTEXT $4 #define CP0_PAGEMASK $5 #define CP0_WIRED $6
@@ -361,6 +362,11 @@
#define CAUSEF_BD (_ULCAST_(1) << 31)
/*
- Bits in the coprocessor 0 EBase register.
- */
+#define EBASE_CPUNUM 0x3ff
+/*
- Bits in the coprocessor 0 config register.
*/
/* Generic bits. */
@@ -548,6 +554,7 @@
#define MIPS_CONF5_MRP (_ULCAST_(1) << 3) #define MIPS_CONF5_LLB (_ULCAST_(1) << 4) #define MIPS_CONF5_MVH (_ULCAST_(1) << 5)
+#define MIPS_CONF5_VP (_ULCAST_(1) << 7)
#define MIPS_CONF5_FRE (_ULCAST_(1) << 8) #define MIPS_CONF5_UFE (_ULCAST_(1) << 9) #define MIPS_CONF5_MSAEN (_ULCAST_(1) << 27)
participants (3)
-
Daniel Schwierzeck
-
Langer, Thomas
-
Paul Burton