On the Loongson-2G/2H/3A/3B there is a hardware flaw that ll/sc and lld/scd is very weak ordering. We should add sync instructions before each ll/lld and after the last sc/scd to workaround. Otherwise, this flaw will cause deadlock occationally (e.g. when doing heavy load test with LTP). We introduced an gcc/as option "-mfix-loongson3-llsc", this option inserts sync before ll, and so some addresses in __ex_table will need to be shift. This is based on the patch from Huacai Chen. --- arch/mips/Makefile | 5 +++++ arch/mips/include/asm/futex.h | 20 ++++++++++++-------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index b6303e48d..360ee1c30 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -194,6 +194,11 @@ cflags-$(CONFIG_CPU_CAVIUM_OCTEON) += -Wa,-march=octeon endif cflags-$(CONFIG_CAVIUM_CN63XXP1) += -Wa,-mfix-cn63xxp1 cflags-$(CONFIG_CPU_BMIPS) += -march=mips32 -Wa,-mips32 -Wa,--trap +ifeq ($(CONFIG_CPU_LOONGSON3),y) +cflags-y += $(call cc-option,-mfix-loongson3-llsc,) +else +cflags-y += $(call cc-option,-mno-fix-loongson3-llsc,) +endif cflags-$(CONFIG_CPU_R4000_WORKAROUNDS) += $(call cc-option,-mfix-r4000,) cflags-$(CONFIG_CPU_R4400_WORKAROUNDS) += $(call cc-option,-mfix-r4400,) diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h index 8eff134b3..27fceaf1d 100644 --- a/arch/mips/include/asm/futex.h +++ b/arch/mips/include/asm/futex.h @@ -18,6 +18,14 @@ #include <asm/errno.h> #include <asm/war.h> +#if defined(__mips_fix_loongson3_llsc) && defined(CONFIG_CPU_LOONGSON3) +# define LL_SHIFT_UA __UA_ADDR "\t(1b+0), 4b \n" \ + __UA_ADDR "\t(1b+4), 4b \n" \ + __UA_ADDR "\t(2b+0), 4b \n" +#else +# define LL_SHIFT_UA __UA_ADDR "\t1b, 4b \n" \ + __UA_ADDR "\t2b, 4b \n" +#endif #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ { \ if (cpu_has_llsc && R10000_LLSC_WAR) { \ @@ -41,8 +49,7 @@ " j 3b \n" \ " .previous \n" \ " .section __ex_table,\"a\" \n" \ - " "__UA_ADDR "\t1b, 4b \n" \ - " "__UA_ADDR "\t2b, 4b \n" \ + LL_SHIFT_UA \ " .previous \n" \ : "=r" (ret), "=&r" (oldval), \ "=" GCC_OFF_SMALL_ASM() (*uaddr) \ @@ -70,8 +77,7 @@ " j 3b \n" \ " .previous \n" \ " .section __ex_table,\"a\" \n" \ - " "__UA_ADDR "\t1b, 4b \n" \ - " "__UA_ADDR "\t2b, 4b \n" \ + LL_SHIFT_UA \ " .previous \n" \ : "=r" (ret), "=&r" (oldval), \ "=" GCC_OFF_SMALL_ASM() (*uaddr) \ @@ -155,8 +161,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, " j 3b \n" " .previous \n" " .section __ex_table,\"a\" \n" - " "__UA_ADDR "\t1b, 4b \n" - " "__UA_ADDR "\t2b, 4b \n" + LL_SHIFT_UA " .previous \n" : "+r" (ret), "=&r" (val), "=" GCC_OFF_SMALL_ASM() (*uaddr) : GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval), @@ -185,8 +190,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, " j 3b \n" " .previous \n" " .section __ex_table,\"a\" \n" - " "__UA_ADDR "\t1b, 4b \n" - " "__UA_ADDR "\t2b, 4b \n" + LL_SHIFT_UA " .previous \n" : "+r" (ret), "=&r" (val), "=" GCC_OFF_SMALL_ASM() (*uaddr) : GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval), -- 2.20.0.rc2