In loongson3_type3_play_dead(), in order to make sure the PC address is correct, use lw to read the low 32 bits first, if the result is not zero, then use ld to read the whole 64 bits, otherwise there maybe exists atomic problem due to write high 32 bits first and then low 32 bits, like this:
high 32 bits (write done) -- only read high 32-bits which is wrong low 32 bits (not yet write done) This problem is especially for Loongson 3A4000+ CPU due to using Mail_Send register which can only send 32 bits data one time. Although it is hard to reproduce, we can do something at the software level to avoid the risks for 3A4000+ CPU, this change has no influence on the other Loongson CPUs. Signed-off-by: Lu Zeng <zen...@loongson.cn> Signed-off-by: Jun Yi <yi...@loongson.cn> Signed-off-by: Tiezhu Yang <yangtie...@loongson.cn> --- arch/mips/loongson64/smp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/mips/loongson64/smp.c b/arch/mips/loongson64/smp.c index 33597d2..e486bbf 100644 --- a/arch/mips/loongson64/smp.c +++ b/arch/mips/loongson64/smp.c @@ -731,9 +731,10 @@ static void loongson3_type3_play_dead(int *state_addr) "1: li %[count], 0x100 \n" /* wait for init loop */ "2: bnez %[count], 2b \n" /* limit mailbox access */ " addiu %[count], -1 \n" - " ld %[initfunc], 0x20(%[base]) \n" /* get PC via mailbox */ + " lw %[initfunc], 0x20(%[base]) \n" /* get PC (low 32 bits) via mailbox */ " beqz %[initfunc], 1b \n" " nop \n" + " ld %[initfunc], 0x20(%[base]) \n" /* get PC (whole 64 bits) via mailbox */ " ld $sp, 0x28(%[base]) \n" /* get SP via mailbox */ " ld $gp, 0x30(%[base]) \n" /* get GP via mailbox */ " ld $a1, 0x38(%[base]) \n" -- 2.1.0