Re: [PATCH V5 8/8] MIPS: Loongson: Introduce and use WAR_LLSC_MB

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




> 在 2018年11月15日,下午3:53,Huacai Chen <chenhc@xxxxxxxxxx> 写道:
> 
> 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).
> 
> This patch is not a minimal change (it is very difficult to make a
> minimal change), but it is a safest change.
> 
> Why disable fix-loongson3-llsc in compiler?
> Because compiler fix will cause problems in kernel's .fixup section.
> 
> Signed-off-by: Huacai Chen <chenhc@xxxxxxxxxx>
> ---
> arch/mips/include/asm/atomic.h  | 36 ++++++++++++++++++++++++++++--------
> arch/mips/include/asm/barrier.h |  6 ++++++
> arch/mips/include/asm/bitops.h  | 15 +++++++++++++++
> arch/mips/include/asm/cmpxchg.h |  9 +++++++--
> arch/mips/include/asm/edac.h    |  5 ++++-
> arch/mips/include/asm/futex.h   | 18 ++++++++++++------
> arch/mips/include/asm/local.h   | 10 ++++++++--
> arch/mips/include/asm/pgtable.h |  5 ++++-
> arch/mips/kernel/syscall.c      |  2 ++
> arch/mips/loongson64/Platform   |  3 +++
> arch/mips/mm/tlbex.c            | 11 +++++++++++
> 11 files changed, 100 insertions(+), 20 deletions(-)
> 
> diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h
> index e8fbfd4..9fbe85f 100644
> --- a/arch/mips/include/asm/atomic.h
> +++ b/arch/mips/include/asm/atomic.h
> @@ -61,13 +61,16 @@ static __inline__ void atomic_##op(int i, atomic_t * v)			      \
> 		__asm__ __volatile__(					      \
> 		"	.set	push					\n"   \
> 		"	.set	"MIPS_ISA_LEVEL"			\n"   \
> -		"1:	ll	%0, %1		# atomic_" #op "	\n"   \
> +		"1:				# atomic_" #op "	\n"   \
> +		__WAR_LLSC_MB						      \
> +		"	ll	%0, %1					\n"   \
> 		"	" #asm_op " %0, %2				\n"   \
> 		"	sc	%0, %1					\n"   \
> 		"\t" __scbeqz "	%0, 1b					\n"   \
> 		"	.set	pop					\n"   \
> 		: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter)	      \
> 		: "Ir" (i));						      \
> +		__asm__ __volatile__(__WAR_LLSC_MB : : :"memory");	      \
> 	} else {							      \
> 		unsigned long flags;					      \
> 									      \
> @@ -88,7 +91,9 @@ static __inline__ int atomic_##op##_return_relaxed(int i, atomic_t * v)	      \
> 		__asm__ __volatile__(					      \
> 		"	.set	push					\n"   \
> 		"	.set	"MIPS_ISA_LEVEL"			\n"   \
> -		"1:	ll	%1, %2		# atomic_" #op "_return	\n"   \
> +		"1:				# atomic_" #op "_return	\n"   \
> +		__WAR_LLSC_MB						      \
> +		"	ll	%1, %2					\n"   \
> 		"	" #asm_op " %0, %1, %3				\n"   \
> 		"	sc	%0, %2					\n"   \
> 		"\t" __scbeqz "	%0, 1b					\n"   \
> @@ -121,7 +126,9 @@ static __inline__ int atomic_fetch_##op##_relaxed(int i, atomic_t * v)	      \
> 		__asm__ __volatile__(					      \
> 		"	.set	push					\n"   \
> 		"	.set	"MIPS_ISA_LEVEL"			\n"   \
> -		"1:	ll	%1, %2		# atomic_fetch_" #op "	\n"   \
> +		"1:				# atomic_fetch_" #op "	\n"   \
> +		__WAR_LLSC_MB						      \
> +		"	ll	%1, %2					\n"   \
> 		"	" #asm_op " %0, %1, %3				\n"   \
> 		"	sc	%0, %2					\n"   \
> 		"\t" __scbeqz "	%0, 1b					\n"   \
> @@ -130,6 +137,7 @@ static __inline__ int atomic_fetch_##op##_relaxed(int i, atomic_t * v)	      \
> 		: "=&r" (result), "=&r" (temp),				      \
> 		  "+" GCC_OFF_SMALL_ASM() (v->counter)			      \
> 		: "Ir" (i));						      \
> +		__asm__ __volatile__(__WAR_LLSC_MB : : :"memory");	      \
> 	} else {							      \
> 		unsigned long flags;					      \
> 									      \
> @@ -193,7 +201,9 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
> 		__asm__ __volatile__(
> 		"	.set	push					\n"
> 		"	.set	"MIPS_ISA_LEVEL"			\n"
> -		"1:	ll	%1, %2		# atomic_sub_if_positive\n"
> +		"1:				# atomic_sub_if_positive\n"
> +		__WAR_LLSC_MB
> +		"	ll	%1, %2					\n"
> 		"	.set	pop					\n"
> 		"	subu	%0, %1, %3				\n"
> 		"	move	%1, %0					\n"
> @@ -259,13 +269,16 @@ static __inline__ void atomic64_##op(long i, atomic64_t * v)		      \
> 		__asm__ __volatile__(					      \
> 		"	.set	push					\n"   \
> 		"	.set	"MIPS_ISA_LEVEL"			\n"   \
> -		"1:	lld	%0, %1		# atomic64_" #op "	\n"   \
> +		"1:				# atomic64_" #op "	\n"   \
> +		__WAR_LLSC_MB						      \
> +		"	lld	%0, %1					\n"   \
> 		"	" #asm_op " %0, %2				\n"   \
> 		"	scd	%0, %1					\n"   \
> 		"\t" __scbeqz "	%0, 1b					\n"   \
> 		"	.set	pop					\n"   \
> 		: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter)	      \
> 		: "Ir" (i));						      \
> +		__asm__ __volatile__(__WAR_LLSC_MB : : :"memory");	      \
> 	} else {							      \
> 		unsigned long flags;					      \
> 									      \
> @@ -286,7 +299,9 @@ static __inline__ long atomic64_##op##_return_relaxed(long i, atomic64_t * v) \
> 		__asm__ __volatile__(					      \
> 		"	.set	push					\n"   \
> 		"	.set	"MIPS_ISA_LEVEL"			\n"   \
> -		"1:	lld	%1, %2		# atomic64_" #op "_return\n"  \
> +		"1:				# atomic64_" #op "_return\n"  \
> +		__WAR_LLSC_MB						      \
> +		"	lld	%1, %2					\n"   \
> 		"	" #asm_op " %0, %1, %3				\n"   \
> 		"	scd	%0, %2					\n"   \
> 		"\t" __scbeqz "	%0, 1b					\n"   \
> @@ -319,7 +334,9 @@ static __inline__ long atomic64_fetch_##op##_relaxed(long i, atomic64_t * v)  \
> 		__asm__ __volatile__(					      \
> 		"	.set	push					\n"   \
> 		"	.set	"MIPS_ISA_LEVEL"			\n"   \
> -		"1:	lld	%1, %2		# atomic64_fetch_" #op "\n"   \
> +		"1:				# atomic64_fetch_" #op "\n"   \
> +		__WAR_LLSC_MB						      \
> +		"	lld	%1, %2					\n"   \
> 		"	" #asm_op " %0, %1, %3				\n"   \
> 		"	scd	%0, %2					\n"   \
> 		"\t" __scbeqz "	%0, 1b					\n"   \
> @@ -328,6 +345,7 @@ static __inline__ long atomic64_fetch_##op##_relaxed(long i, atomic64_t * v)  \
> 		: "=&r" (result), "=&r" (temp),				      \
> 		  "+" GCC_OFF_SMALL_ASM() (v->counter)			      \
> 		: "Ir" (i));						      \
> +		__asm__ __volatile__(__WAR_LLSC_MB : : :"memory");	      \
> 	} else {							      \
> 		unsigned long flags;					      \
> 									      \
> @@ -392,7 +410,9 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
> 		__asm__ __volatile__(
> 		"	.set	push					\n"
> 		"	.set	"MIPS_ISA_LEVEL"			\n"
> -		"1:	lld	%1, %2		# atomic64_sub_if_positive\n"
> +		"1:				# atomic64_sub_if_positive\n"
> +		__WAR_LLSC_MB
> +		"	lld	%1, %2					\n"
> 		"	dsubu	%0, %1, %3				\n"
> 		"	move	%1, %0					\n"
> 		"	bltz	%0, 1f					\n"
> diff --git a/arch/mips/include/asm/barrier.h b/arch/mips/include/asm/barrier.h
> index a5eb1bb..d892094 100644
> --- a/arch/mips/include/asm/barrier.h
> +++ b/arch/mips/include/asm/barrier.h
> @@ -203,6 +203,12 @@
> #define __WEAK_LLSC_MB		"		\n"
> #endif
> 
> +#if defined(CONFIG_LOONGSON3) && defined(CONFIG_SMP) /* Loongson-3's LLSC workaround */
> +#define __WAR_LLSC_MB		"	sync	\n"
> +#else
> +#define __WAR_LLSC_MB		"		\n"
> +#endif
> +
> #define smp_llsc_mb()	__asm__ __volatile__(__WEAK_LLSC_MB : : :"memory")
> 
> #ifdef CONFIG_CPU_CAVIUM_OCTEON
> diff --git a/arch/mips/include/asm/bitops.h b/arch/mips/include/asm/bitops.h
> index f2a840f..4943f52 100644
> --- a/arch/mips/include/asm/bitops.h
> +++ b/arch/mips/include/asm/bitops.h
> @@ -71,18 +71,21 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
> 	} else if (kernel_uses_llsc && __builtin_constant_p(bit)) {
> 		do {
> 			__asm__ __volatile__(
> +			__WAR_LLSC_MB
> 			"	" __LL "%0, %1		# set_bit	\n"
> 			"	" __INS "%0, %3, %2, 1			\n"
> 			"	" __SC "%0, %1				\n"
> 			: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m)
> 			: "ir" (bit), "r" (~0));
> 		} while (unlikely(!temp));
> +		__asm__ __volatile__(__WAR_LLSC_MB : : :"memory");
> #endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */
> 	} else if (kernel_uses_llsc) {
> 		do {
> 			__asm__ __volatile__(
> 			"	.set	push				\n"
> 			"	.set	"MIPS_ISA_ARCH_LEVEL"		\n"
> +			__WAR_LLSC_MB
> 			"	" __LL "%0, %1		# set_bit	\n"
> 			"	or	%0, %2				\n"
> 			"	" __SC	"%0, %1				\n"
> @@ -90,6 +93,7 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
> 			: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m)
> 			: "ir" (1UL << bit));
> 		} while (unlikely(!temp));
> +		__asm__ __volatile__(__WAR_LLSC_MB : : :"memory");
> 	} else
> 		__mips_set_bit(nr, addr);
> }
> @@ -125,18 +129,21 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
> 	} else if (kernel_uses_llsc && __builtin_constant_p(bit)) {
> 		do {
> 			__asm__ __volatile__(
> +			__WAR_LLSC_MB
> 			"	" __LL "%0, %1		# clear_bit	\n"
> 			"	" __INS "%0, $0, %2, 1			\n"
> 			"	" __SC "%0, %1				\n"
> 			: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m)
> 			: "ir" (bit));
> 		} while (unlikely(!temp));
> +		__asm__ __volatile__(__WAR_LLSC_MB : : :"memory");
> #endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */
> 	} else if (kernel_uses_llsc) {
> 		do {
> 			__asm__ __volatile__(
> 			"	.set	push				\n"
> 			"	.set	"MIPS_ISA_ARCH_LEVEL"		\n"
> +			__WAR_LLSC_MB
> 			"	" __LL "%0, %1		# clear_bit	\n"
> 			"	and	%0, %2				\n"
> 			"	" __SC "%0, %1				\n"
> @@ -144,6 +151,7 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
> 			: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m)
> 			: "ir" (~(1UL << bit)));
> 		} while (unlikely(!temp));
> +		__asm__ __volatile__(__WAR_LLSC_MB : : :"memory");
> 	} else
> 		__mips_clear_bit(nr, addr);
> }
> @@ -197,6 +205,7 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
> 			__asm__ __volatile__(
> 			"	.set	push				\n"
> 			"	.set	"MIPS_ISA_ARCH_LEVEL"		\n"
> +			__WAR_LLSC_MB
> 			"	" __LL "%0, %1		# change_bit	\n"
> 			"	xor	%0, %2				\n"
> 			"	" __SC	"%0, %1				\n"
> @@ -204,6 +213,7 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
> 			: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m)
> 			: "ir" (1UL << bit));
> 		} while (unlikely(!temp));
> +		__asm__ __volatile__(__WAR_LLSC_MB : : :"memory");
> 	} else
> 		__mips_change_bit(nr, addr);
> }
> @@ -248,6 +258,7 @@ static inline int test_and_set_bit(unsigned long nr,
> 			__asm__ __volatile__(
> 			"	.set	push				\n"
> 			"	.set	"MIPS_ISA_ARCH_LEVEL"		\n"
> +			__WAR_LLSC_MB
> 			"	" __LL "%0, %1	# test_and_set_bit	\n"
> 			"	or	%2, %0, %3			\n"
> 			"	" __SC	"%2, %1				\n"
> @@ -304,6 +315,7 @@ static inline int test_and_set_bit_lock(unsigned long nr,
> 			__asm__ __volatile__(
> 			"	.set	push				\n"
> 			"	.set	"MIPS_ISA_ARCH_LEVEL"		\n"
> +			__WAR_LLSC_MB
> 			"	" __LL "%0, %1	# test_and_set_bit	\n"
> 			"	or	%2, %0, %3			\n"
> 			"	" __SC	"%2, %1				\n"
> @@ -361,6 +373,7 @@ static inline int test_and_clear_bit(unsigned long nr,
> 
> 		do {
> 			__asm__ __volatile__(
> +			__WAR_LLSC_MB
> 			"	" __LL	"%0, %1 # test_and_clear_bit	\n"
> 			"	" __EXT "%2, %0, %3, 1			\n"
> 			"	" __INS "%0, $0, %3, 1			\n"
> @@ -378,6 +391,7 @@ static inline int test_and_clear_bit(unsigned long nr,
> 			__asm__ __volatile__(
> 			"	.set	push				\n"
> 			"	.set	"MIPS_ISA_ARCH_LEVEL"		\n"
> +			__WAR_LLSC_MB
> 			"	" __LL	"%0, %1 # test_and_clear_bit	\n"
> 			"	or	%2, %0, %3			\n"
> 			"	xor	%2, %3				\n"
> @@ -437,6 +451,7 @@ static inline int test_and_change_bit(unsigned long nr,
> 			__asm__ __volatile__(
> 			"	.set	push				\n"
> 			"	.set	"MIPS_ISA_ARCH_LEVEL"		\n"
> +			__WAR_LLSC_MB
> 			"	" __LL	"%0, %1 # test_and_change_bit	\n"
> 			"	xor	%2, %0, %3			\n"
> 			"	" __SC	"\t%2, %1			\n"
> diff --git a/arch/mips/include/asm/cmpxchg.h b/arch/mips/include/asm/cmpxchg.h
> index 638de0c..8bf2f23 100644
> --- a/arch/mips/include/asm/cmpxchg.h
> +++ b/arch/mips/include/asm/cmpxchg.h
> @@ -49,7 +49,9 @@ extern unsigned long __xchg_called_with_bad_pointer(void)
> 		"	.set	noat				\n"	\
> 		"	.set	push				\n"	\
> 		"	.set	" MIPS_ISA_ARCH_LEVEL "		\n"	\
> -		"1:	" ld "	%0, %2		# __xchg_asm	\n"	\
> +		"1:				# __xchg_asm	\n"	\
> +		__WAR_LLSC_MB						\
> +		"	" ld "	%0, %2				\n"	\
> 		"	.set	pop				\n"	\
> 		"	move	$1, %z3				\n"	\
> 		"	.set	" MIPS_ISA_ARCH_LEVEL "		\n"	\
> @@ -120,7 +122,9 @@ static inline unsigned long __xchg(volatile void *ptr, unsigned long x,
> 		"	.set	noat				\n"	\
> 		"	.set	push				\n"	\
> 		"	.set	"MIPS_ISA_ARCH_LEVEL"		\n"	\
> -		"1:	" ld "	%0, %2		# __cmpxchg_asm \n"	\
> +		"1:				# __cmpxchg_asm \n"	\
> +		__WAR_LLSC_MB						\
> +		"	" ld "	%0, %2				\n"	\
> 		"	bne	%0, %z3, 2f			\n"	\
> 		"	.set	pop				\n"	\
> 		"	move	$1, %z4				\n"	\
> @@ -129,6 +133,7 @@ static inline unsigned long __xchg(volatile void *ptr, unsigned long x,
> 		"\t" __scbeqz "	$1, 1b				\n"	\
> 		"	.set	pop				\n"	\
> 		"2:						\n"	\
> +		__WAR_LLSC_MB						\
> 		: "=&r" (__ret), "=" GCC_OFF_SMALL_ASM() (*m)		\
> 		: GCC_OFF_SMALL_ASM() (*m), "Jr" (old), "Jr" (new)		\
> 		: "memory");						\
> diff --git a/arch/mips/include/asm/edac.h b/arch/mips/include/asm/edac.h
> index c5d1477..59b776d 100644
> --- a/arch/mips/include/asm/edac.h
> +++ b/arch/mips/include/asm/edac.h
> @@ -23,13 +23,16 @@ static inline void edac_atomic_scrub(void *va, u32 size)
> 		__asm__ __volatile__ (
> 		"	.set	push					\n"
> 		"	.set	mips2					\n"
> -		"1:	ll	%0, %1		# edac_atomic_scrub	\n"
> +		"1:				# edac_atomic_scrub	\n"
> +		__WAR_LLSC_MB
> +		"	ll	%0, %1					\n"
> 		"	addu	%0, $0					\n"
> 		"	sc	%0, %1					\n"
> 		"	beqz	%0, 1b					\n"
> 		"	.set	pop					\n"
> 		: "=&r" (temp), "=" GCC_OFF_SMALL_ASM() (*virt_addr)
> 		: GCC_OFF_SMALL_ASM() (*virt_addr));
> +		__asm__ __volatile__(__WAR_LLSC_MB : : :"memory");
> 
> 		virt_addr++;
> 	}
> diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h
> index 8eff134..9887c34 100644
> --- a/arch/mips/include/asm/futex.h
> +++ b/arch/mips/include/asm/futex.h
> @@ -55,7 +55,9 @@
> 		"	.set	noat				\n"	\
> 		"	.set	push				\n"	\
> 		"	.set	"MIPS_ISA_ARCH_LEVEL"		\n"	\
> -		"1:	"user_ll("%1", "%4")" # __futex_atomic_op\n"	\
> +		"1:				 # __futex_atomic_op\n"	\
> +		__WAR_LLSC_MB						\
> +		"	"user_ll("%1", "%4")"			\n"	\
> 		"	.set	pop				\n"	\
> 		"	" insn	"				\n"	\
> 		"	.set	"MIPS_ISA_ARCH_LEVEL"		\n"	\
> @@ -70,8 +72,9 @@
> 		"	j	3b				\n"	\
> 		"	.previous				\n"	\
> 		"	.section __ex_table,\"a\"		\n"	\
> -		"	"__UA_ADDR "\t1b, 4b			\n"	\
> -		"	"__UA_ADDR "\t2b, 4b			\n"	\
> +		"	"__UA_ADDR "\t(1b + 0), 4b		\n"	\
> +		"	"__UA_ADDR "\t(1b + 4), 4b		\n"	\
> +		"	"__UA_ADDR "\t(2b + 0), 4b		\n"	\
> 		"	.previous				\n"	\
> 		: "=r" (ret), "=&r" (oldval),				\
> 		  "=" GCC_OFF_SMALL_ASM() (*uaddr)				\
> @@ -169,7 +172,9 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> 		"	.set	noat					\n"
> 		"	.set	push					\n"
> 		"	.set	"MIPS_ISA_ARCH_LEVEL"			\n"
> -		"1:	"user_ll("%1", "%3")"				\n"
> +		"1:							\n"
> +		__WAR_LLSC_MB
> +		"	"user_ll("%1", "%3")"				\n"
> 		"	bne	%1, %z4, 3f				\n"
> 		"	.set	pop					\n"
> 		"	move	$1, %z5					\n"
> @@ -185,8 +190,9 @@ 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"
> +		"	"__UA_ADDR "\t(1b + 0), 4b			\n"
> +		"	"__UA_ADDR "\t(1b + 4), 4b			\n"
> +		"	"__UA_ADDR "\t(2b + 0), 4b			\n"
> 		"	.previous					\n"
> 		: "+r" (ret), "=&r" (val), "=" GCC_OFF_SMALL_ASM() (*uaddr)
> 		: GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval),
> diff --git a/arch/mips/include/asm/local.h b/arch/mips/include/asm/local.h
> index 02783e1..6b1936b 100644
> --- a/arch/mips/include/asm/local.h
> +++ b/arch/mips/include/asm/local.h
> @@ -52,7 +52,9 @@ static __inline__ long local_add_return(long i, local_t * l)
> 		__asm__ __volatile__(
> 		"	.set	push					\n"
> 		"	.set	"MIPS_ISA_ARCH_LEVEL"			\n"
> -		"1:"	__LL	"%1, %2		# local_add_return	\n"
> +		"1:				# local_add_return	\n"
> +			__WAR_LLSC_MB
> +			__LL	"%1, %2					\n"
> 		"	addu	%0, %1, %3				\n"
> 			__SC	"%0, %2					\n"
> 		"	beqz	%0, 1b					\n"
> @@ -61,6 +63,7 @@ static __inline__ long local_add_return(long i, local_t * l)
> 		: "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
> 		: "Ir" (i), "m" (l->a.counter)
> 		: "memory");
> +		__asm__ __volatile__(__WAR_LLSC_MB : : :"memory");
> 	} else {
> 		unsigned long flags;
> 
> @@ -99,7 +102,9 @@ static __inline__ long local_sub_return(long i, local_t * l)
> 		__asm__ __volatile__(
> 		"	.set	push					\n"
> 		"	.set	"MIPS_ISA_ARCH_LEVEL"			\n"
> -		"1:"	__LL	"%1, %2		# local_sub_return	\n"
> +		"1:				# local_sub_return	\n"
> +			__WAR_LLSC_MB
> +			__LL	"%1, %2					\n"
> 		"	subu	%0, %1, %3				\n"
> 			__SC	"%0, %2					\n"
> 		"	beqz	%0, 1b					\n"
> @@ -108,6 +113,7 @@ static __inline__ long local_sub_return(long i, local_t * l)
> 		: "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
> 		: "Ir" (i), "m" (l->a.counter)
> 		: "memory");
> +		__asm__ __volatile__(__WAR_LLSC_MB : : :"memory");
> 	} else {
> 		unsigned long flags;
> 
> diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
> index 57933fc..fcd3964 100644
> --- a/arch/mips/include/asm/pgtable.h
> +++ b/arch/mips/include/asm/pgtable.h
> @@ -232,7 +232,9 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)
> 			"	.set	push				\n"
> 			"	.set	"MIPS_ISA_ARCH_LEVEL"		\n"
> 			"	.set	noreorder			\n"
> -			"1:"	__LL	"%[tmp], %[buddy]		\n"
> +			"1:						\n"
> +				__WAR_LLSC_MB
> +				__LL	"%[tmp], %[buddy]		\n"
> 			"	bnez	%[tmp], 2f			\n"
> 			"	 or	%[tmp], %[tmp], %[global]	\n"
> 				__SC	"%[tmp], %[buddy]		\n"
> @@ -242,6 +244,7 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)
> 			"	.set	pop				\n"
> 			: [buddy] "+m" (buddy->pte), [tmp] "=&r" (tmp)
> 			: [global] "r" (page_global));
> +			__asm__ __volatile__(__WAR_LLSC_MB : : :"memory");
> 		}
> #else /* !CONFIG_SMP */
> 		if (pte_none(*buddy))
> diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
> index 41a0db0..6fa3188 100644
> --- a/arch/mips/kernel/syscall.c
> +++ b/arch/mips/kernel/syscall.c
> @@ -137,6 +137,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"
> +		__WAR_LLSC_MB
> 		user_ll("%[old]", "(%[addr])")
> 		"	move	%[tmp], %[new]				\n"
> 		"2:							\n"
> @@ -160,6 +161,7 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new)
> 		  [new] "r" (new),
> 		  [efault] "i" (-EFAULT)
> 		: "memory");
> +		__asm__ __volatile__(__WAR_LLSC_MB : : :"memory");
> 	} else {
> 		do {
> 			preempt_disable();
> diff --git a/arch/mips/loongson64/Platform b/arch/mips/loongson64/Platform
> index 0fce460..3700dcf 100644
> --- a/arch/mips/loongson64/Platform
> +++ b/arch/mips/loongson64/Platform
> @@ -23,6 +23,9 @@ ifdef CONFIG_CPU_LOONGSON2F_WORKAROUNDS
> endif
> 
> cflags-$(CONFIG_CPU_LOONGSON3)	+= -Wa,--trap
> +ifneq ($(call as-option,-Wa$(comma)-mfix-loongson3-llsc,),)
> +  cflags-$(CONFIG_CPU_LOONGSON3) += -Wa$(comma)-mno-fix-loongson3-llsc
> +endif
> #

fix-loongson3-llsc is not in upstream yet.

And why this option generates .fixup section?

> # binutils from v2.25 on and gcc starting from v4.9.0 treat -march=loongson3a
> # as MIPS64 R2; older versions as just R1.  This leaves the possibility open
> diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
> index 0677142..74941b2 100644
> --- a/arch/mips/mm/tlbex.c
> +++ b/arch/mips/mm/tlbex.c
> @@ -931,6 +931,8 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
> 		 * to mimic that here by taking a load/istream page
> 		 * fault.
> 		 */
> +		if (current_cpu_type() == CPU_LOONGSON3)
> +			uasm_i_sync(p, 0);
> 		UASM_i_LA(p, ptr, (unsigned long)tlb_do_page_fault_0);
> 		uasm_i_jr(p, ptr);
> 
> @@ -1555,6 +1557,7 @@ static void build_loongson3_tlb_refill_handler(void)
> 
> 	if (check_for_high_segbits) {
> 		uasm_l_large_segbits_fault(&l, p);
> +		uasm_i_sync(&p, 0);
> 		UASM_i_LA(&p, K1, (unsigned long)tlb_do_page_fault_0);
> 		uasm_i_jr(&p, K1);
> 		uasm_i_nop(&p);
> @@ -1645,6 +1648,8 @@ static void
> iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr)
> {
> #ifdef CONFIG_SMP
> +	if (current_cpu_type() == CPU_LOONGSON3)
> +		uasm_i_sync(p, 0);

@huacai, I guess we should set these 2 line a macro?
#ifdef CONFIG_CPU_LOONGSON3
#define LS_UASM_I_SYNC_PTR uasm_i_sync(&p, 0)
#else 
#define LS_UASM_I_SYNC_PTR
#endif

> # ifdef CONFIG_PHYS_ADDR_T_64BIT
> 	if (cpu_has_64bits)
> 		uasm_i_lld(p, pte, 0, ptr);
> @@ -2258,6 +2263,8 @@ static void build_r4000_tlb_load_handler(void)
> #endif
> 
> 	uasm_l_nopage_tlbl(&l, p);
> +	if (current_cpu_type() == CPU_LOONGSON3)
> +		uasm_i_sync(&p, 0);
> 	build_restore_work_registers(&p);
> #ifdef CONFIG_CPU_MICROMIPS
> 	if ((unsigned long)tlb_do_page_fault_0 & 1) {
> @@ -2312,6 +2319,8 @@ static void build_r4000_tlb_store_handler(void)
> #endif
> 
> 	uasm_l_nopage_tlbs(&l, p);
> +	if (current_cpu_type() == CPU_LOONGSON3)
> +		uasm_i_sync(&p, 0);
> 	build_restore_work_registers(&p);
> #ifdef CONFIG_CPU_MICROMIPS
> 	if ((unsigned long)tlb_do_page_fault_1 & 1) {
> @@ -2367,6 +2376,8 @@ static void build_r4000_tlb_modify_handler(void)
> #endif
> 
> 	uasm_l_nopage_tlbm(&l, p);
> +	if (current_cpu_type() == CPU_LOONGSON3)
> +		uasm_i_sync(&p, 0);
> 	build_restore_work_registers(&p);
> #ifdef CONFIG_CPU_MICROMIPS
> 	if ((unsigned long)tlb_do_page_fault_1 & 1) {


[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux