linux-mips
[Top] [All Lists]

[PATCH 2/3] loongson64: fix ll/sc bug of loongson3 in inline asm

Subject: [PATCH 2/3] loongson64: fix ll/sc bug of loongson3 in inline asm
From: Huang Pei <huangpei@loongson.cn>
Date: Sat, 12 Jan 2019 09:40:31 +0800
+. without __LS3A_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.

+. __LS3A_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 enought

+. change __WEAK_LLSC_MB in futex.h to support same function as
__LS_WAR_LLSC

Signed-off-by: Huang Pei <huangpei@loongson.cn>
---
 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..ba48a50 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__(                                         \
+               __LS3A_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"   \
+               __LS3A_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"   \
+               __LS3A_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"   \
+               __LS3A_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"   \
+               __LS3A_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"   \
+               __LS3A_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..ba50277 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)) {
+               __ls3a_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) {
+               __ls3a_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)) {
+               __ls3a_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) {
+               __ls3a_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;
 
+               __ls3a_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;
 
+               __ls3a_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..9141fa2 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"
+               __LS3A_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..0706ac3 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"     \
+               __LS3A_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"
+               __LS3A_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..afc64b2 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"
+               __LS3A_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"
+               __LS3A_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..12a8217 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"
+                       __LS3A_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..b1a0fd3 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"
+               __LS3A_WAR_LLSC
                user_ll("%[old]", "(%[addr])")
                "       move    %[tmp], %[new]                          \n"
                "2:                                                     \n"
-- 
2.7.4


--MP_//bnUSBHJc++7d8CF.feLcdS
Content-Type: text/x-patch
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename=0003-loongson64-fix-ll-sc-bug-of-Loongson-3-in-handle_tlb.patch

<Prev in Thread] Current Thread [Next in Thread>
  • [PATCH 2/3] loongson64: fix ll/sc bug of loongson3 in inline asm, Huang Pei <=