From 5bc7601982195c899fd8e3a5cf9a2ea1e8a326af Mon Sep 17 00:00:00 2001 From: Huang Pei Date: Sat, 12 Jan 2019 09:40:31 +0800 Subject: [PATCH 2/3] loongson64: fix ll/sc bug of Loongson 3 in inline asm +. without __LS3_WAR_LLSC before ll, and __LS_WAR_LLSC before target from branch ins between ll and sc, two ll/sc operation on same variable can success both, which is clearly wrong. +. __LS3_WAR_LLSC is needed for Loongson 3 CPU before 3A2000(NOT including 3A2000) +. __LS_WAR_LLSC is needed all Looongson 3 CPU +. old patch fix cmpxchg.h, but now smp_mb__before_llsc and smp_llsc_mb in cmpxchg.h is enough +. change __WEAK_LLSC_MB in futex.h to support same function as __LS_WAR_LLSC Signed-off-by: Huang Pei --- arch/mips/include/asm/atomic.h | 6 ++++++ arch/mips/include/asm/bitops.h | 6 ++++++ arch/mips/include/asm/edac.h | 1 + arch/mips/include/asm/futex.h | 4 +++- arch/mips/include/asm/local.h | 2 ++ arch/mips/include/asm/pgtable.h | 2 ++ arch/mips/kernel/syscall.c | 1 + 7 files changed, 21 insertions(+), 1 deletion(-) diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h index d4ea7a5..29068ad 100644 --- a/arch/mips/include/asm/atomic.h +++ b/arch/mips/include/asm/atomic.h @@ -59,6 +59,7 @@ static __inline__ void atomic_##op(int i, atomic_t * v) \ int temp; \ \ __asm__ __volatile__( \ + __LS3_WAR_LLSC \ " .set "MIPS_ISA_LEVEL" \n" \ "1: ll %0, %1 # atomic_" #op " \n" \ " " #asm_op " %0, %2 \n" \ @@ -86,6 +87,7 @@ static __inline__ int atomic_##op##_return_relaxed(int i, atomic_t * v) \ \ __asm__ __volatile__( \ " .set "MIPS_ISA_LEVEL" \n" \ + __LS3_WAR_LLSC \ "1: ll %1, %2 # atomic_" #op "_return \n" \ " " #asm_op " %0, %1, %3 \n" \ " sc %0, %2 \n" \ @@ -118,6 +120,7 @@ static __inline__ int atomic_fetch_##op##_relaxed(int i, atomic_t * v) \ \ __asm__ __volatile__( \ " .set "MIPS_ISA_LEVEL" \n" \ + __LS3_WAR_LLSC \ "1: ll %1, %2 # atomic_fetch_" #op " \n" \ " " #asm_op " %0, %1, %3 \n" \ " sc %0, %2 \n" \ @@ -253,6 +256,7 @@ static __inline__ void atomic64_##op(long i, atomic64_t * v) \ \ __asm__ __volatile__( \ " .set "MIPS_ISA_LEVEL" \n" \ + __LS3_WAR_LLSC \ "1: lld %0, %1 # atomic64_" #op " \n" \ " " #asm_op " %0, %2 \n" \ " scd %0, %1 \n" \ @@ -279,6 +283,7 @@ static __inline__ long atomic64_##op##_return_relaxed(long i, atomic64_t * v) \ \ __asm__ __volatile__( \ " .set "MIPS_ISA_LEVEL" \n" \ + __LS3_WAR_LLSC \ "1: lld %1, %2 # atomic64_" #op "_return\n" \ " " #asm_op " %0, %1, %3 \n" \ " scd %0, %2 \n" \ @@ -311,6 +316,7 @@ static __inline__ long atomic64_fetch_##op##_relaxed(long i, atomic64_t * v) \ \ __asm__ __volatile__( \ " .set "MIPS_ISA_LEVEL" \n" \ + __LS3_WAR_LLSC \ "1: lld %1, %2 # atomic64_fetch_" #op "\n" \ " " #asm_op " %0, %1, %3 \n" \ " scd %0, %2 \n" \ diff --git a/arch/mips/include/asm/bitops.h b/arch/mips/include/asm/bitops.h index da1b8718..075fc52 100644 --- a/arch/mips/include/asm/bitops.h +++ b/arch/mips/include/asm/bitops.h @@ -68,6 +68,7 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr) : "ir" (1UL << bit), GCC_OFF_SMALL_ASM() (*m)); #if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) } else if (kernel_uses_llsc && __builtin_constant_p(bit)) { + __ls3_war_llsc(); do { __asm__ __volatile__( " " __LL "%0, %1 # set_bit \n" @@ -78,6 +79,7 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr) } while (unlikely(!temp)); #endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */ } else if (kernel_uses_llsc) { + __ls3_war_llsc(); do { __asm__ __volatile__( " .set "MIPS_ISA_ARCH_LEVEL" \n" @@ -120,6 +122,7 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr) : "ir" (~(1UL << bit))); #if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) } else if (kernel_uses_llsc && __builtin_constant_p(bit)) { + __ls3_war_llsc(); do { __asm__ __volatile__( " " __LL "%0, %1 # clear_bit \n" @@ -130,6 +133,7 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr) } while (unlikely(!temp)); #endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */ } else if (kernel_uses_llsc) { + __ls3_war_llsc(); do { __asm__ __volatile__( " .set "MIPS_ISA_ARCH_LEVEL" \n" @@ -188,6 +192,7 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr) unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG); unsigned long temp; + __ls3_war_llsc(); do { __asm__ __volatile__( " .set "MIPS_ISA_ARCH_LEVEL" \n" @@ -291,6 +296,7 @@ static inline int test_and_set_bit_lock(unsigned long nr, unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG); unsigned long temp; + __ls3_war_llsc(); do { __asm__ __volatile__( " .set "MIPS_ISA_ARCH_LEVEL" \n" diff --git a/arch/mips/include/asm/edac.h b/arch/mips/include/asm/edac.h index fc46776..6cf3f3e 100644 --- a/arch/mips/include/asm/edac.h +++ b/arch/mips/include/asm/edac.h @@ -22,6 +22,7 @@ static inline void edac_atomic_scrub(void *va, u32 size) __asm__ __volatile__ ( " .set mips2 \n" + __LS3_WAR_LLSC "1: ll %0, %1 # edac_atomic_scrub \n" " addu %0, $0 \n" " sc %0, %1 \n" diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h index a9e61ea..e390c68 100644 --- a/arch/mips/include/asm/futex.h +++ b/arch/mips/include/asm/futex.h @@ -54,6 +54,7 @@ " .set push \n" \ " .set noat \n" \ " .set "MIPS_ISA_ARCH_LEVEL" \n" \ + __LS3_WAR_LLSC \ "1: "user_ll("%1", "%4")" # __futex_atomic_op\n" \ " .set mips0 \n" \ " " insn " \n" \ @@ -167,6 +168,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, " .set push \n" " .set noat \n" " .set "MIPS_ISA_ARCH_LEVEL" \n" + __LS3_WAR_LLSC "1: "user_ll("%1", "%3")" \n" " bne %1, %z4, 3f \n" " .set mips0 \n" @@ -174,8 +176,8 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, " .set "MIPS_ISA_ARCH_LEVEL" \n" "2: "user_sc("$1", "%2")" \n" " beqz $1, 1b \n" - __WEAK_LLSC_MB "3: \n" + __WEAK_LLSC_MB " .insn \n" " .set pop \n" " .section .fixup,\"ax\" \n" diff --git a/arch/mips/include/asm/local.h b/arch/mips/include/asm/local.h index ac8264e..dea04b5 100644 --- a/arch/mips/include/asm/local.h +++ b/arch/mips/include/asm/local.h @@ -50,6 +50,7 @@ static __inline__ long local_add_return(long i, local_t * l) __asm__ __volatile__( " .set "MIPS_ISA_ARCH_LEVEL" \n" + __LS3_WAR_LLSC "1:" __LL "%1, %2 # local_add_return \n" " addu %0, %1, %3 \n" __SC "%0, %2 \n" @@ -95,6 +96,7 @@ static __inline__ long local_sub_return(long i, local_t * l) __asm__ __volatile__( " .set "MIPS_ISA_ARCH_LEVEL" \n" + __LS3_WAR_LLSC "1:" __LL "%1, %2 # local_sub_return \n" " subu %0, %1, %3 \n" __SC "%0, %2 \n" diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index 129e032..6ceb49b 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -233,6 +233,7 @@ static inline void set_pte(pte_t *ptep, pte_t pteval) " .set "MIPS_ISA_ARCH_LEVEL" \n" " .set push \n" " .set noreorder \n" + __LS3_WAR_LLSC "1:" __LL "%[tmp], %[buddy] \n" " bnez %[tmp], 2f \n" " or %[tmp], %[tmp], %[global] \n" @@ -240,6 +241,7 @@ static inline void set_pte(pte_t *ptep, pte_t pteval) " beqz %[tmp], 1b \n" " nop \n" "2: \n" + __LS_WAR_LLSC " .set pop \n" " .set mips0 \n" : [buddy] "+m" (buddy->pte), [tmp] "=&r" (tmp) diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 69c17b5..25fad03 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -135,6 +135,7 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new) " .set "MIPS_ISA_ARCH_LEVEL" \n" " li %[err], 0 \n" "1: \n" + __LS3_WAR_LLSC user_ll("%[old]", "(%[addr])") " move %[tmp], %[new] \n" "2: \n" -- 2.7.4