Skip to contentSkip to conversation

: MIPS: Adjust set_pte() SMP fix to handle R10000_LLSC_WAR

PATCH New Joshua Kinard 1 participant 1 message Sep 7, 2015 MIPS

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 : MIPS: Adjust set_pte() SMP fix to handle R10000_LLSC_WAR

From: Joshua Kinard <[email protected]>

Update the recent changes to set_pte() that were added in 46011e6ea392 to handle R10000_LLSC_WAR, and format the assembly to match other areas of the MIPS tree using the same WAR.

This also incorporates a patch recently sent in my Markos Chandras, "Remove local LL/SC preprocessor variants", so that patch doesn't need to be applied if this one is accepted.

Fixes 46011e6ea392 ("MIPS: Make set_pte() SMP safe.)
Cc Markos Chandras <[email protected]>
Cc David Daney <[email protected]>
---
 arch/mips/include/asm/pgtable.h |   52 ++++++++++++++++++------------
 1 file changed, 32 insertions(+), 20 deletions(-)

Not sure if 'kernel_uses_llsc' or 'cpu_has_llsc' is appropriate for the if conditional. I've seen both used in the tree w/ the R10000_LLSC_WAR construct.

Note: The set_pte() fix appears to be needed for IP27 to boot, so the original patch and this one may need to be backported. Otherwise, the heavy disk I/O lockup bug I've mentioned in the past has a higher chance of triggering and freezing the machine solid, especially if mdraid is rebuilding a disk. The set_pte() fix won't address that bug, but at least mdraid was able to finish the rebuild after it was applied.

linux-mips-set_pte-smp-r10k-war.patch

arch/mips/include/asm/pgtable.h +32 -20
index 8957f15..560bc74 100644
@@ -187,30 +187,42 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)
 		 * For SMP, multiple CPUs can race, so we need to do
 		 * this atomically.
 		 */
-#ifdef CONFIG_64BIT
-#define LL_INSN "lld"
-#define SC_INSN "scd"
-#else /* CONFIG_32BIT */
-#define LL_INSN "ll"
-#define SC_INSN "sc"
-#endif
 		unsigned long page_global = _PAGE_GLOBAL;
 		unsigned long tmp;
 
-		__asm__ __volatile__ (
-			"	.set	push\n"
-			"	.set	noreorder\n"
-			"1:	" LL_INSN "	%[tmp], %[buddy]\n"
-			"	bnez	%[tmp], 2f\n"
-			"	 or	%[tmp], %[tmp], %[global]\n"
-			"	" SC_INSN "	%[tmp], %[buddy]\n"
-			"	beqz	%[tmp], 1b\n"
-			"	 nop\n"
-			"2:\n"
-			"	.set pop"
-			: [buddy] "+m" (buddy->pte),
-			  [tmp] "=&r" (tmp)
+		if (kernel_uses_llsc && R10000_LLSC_WAR) {
+			__asm__ __volatile__ (
+			"	.set	arch=r4000			\n"
+			"	.set	push				\n"
+			"	.set	noreorder			\n"
+			"1:"	__LL	"%[tmp], %[buddy]		\n"
+			"	bnez	%[tmp], 2f			\n"
+			"	 or	%[tmp], %[tmp], %[global]	\n"
+				__SC	"%[tmp], %[buddy]		\n"
+			"	beqzl	%[tmp], 1b			\n"
+			"	nop					\n"
+			"2:						\n"
+			"	.set	pop				\n"
+			"	.set	mips0				\n"
+			: [buddy] "+m" (buddy->pte), [tmp] "=&r" (tmp)
+			: [global] "r" (page_global));
+		} else if (kernel_uses_llsc) {
+			__asm__ __volatile__ (
+			"	.set	"MIPS_ISA_ARCH_LEVEL"		\n"
+			"	.set	push				\n"
+			"	.set	noreorder			\n"
+			"1:"	__LL	"%[tmp], %[buddy]		\n"
+			"	bnez	%[tmp], 2f			\n"
+			"	 or	%[tmp], %[tmp], %[global]	\n"
+				__SC	"%[tmp], %[buddy]		\n"
+			"	beqz	%[tmp], 1b			\n"
+			"	nop					\n"
+			"2:						\n"
+			"	.set	pop				\n"
+			"	.set	mips0				\n"
+			: [buddy] "+m" (buddy->pte), [tmp] "=&r" (tmp)
 			: [global] "r" (page_global));
+		}
 #else /* !CONFIG_SMP */
 		if (pte_none(*buddy))
 			pte_val(*buddy) = pte_val(*buddy) | _PAGE_GLOBAL;