|
@@ -182,8 +182,39 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)
|
|
|
* Make sure the buddy is global too (if it's !none,
|
|
|
* it better already be global)
|
|
|
*/
|
|
|
+#ifdef CONFIG_SMP
|
|
|
+ /*
|
|
|
+ * 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)
|
|
|
+ : [global] "r" (page_global));
|
|
|
+#else /* !CONFIG_SMP */
|
|
|
if (pte_none(*buddy))
|
|
|
pte_val(*buddy) = pte_val(*buddy) | _PAGE_GLOBAL;
|
|
|
+#endif /* CONFIG_SMP */
|
|
|
}
|
|
|
#endif
|
|
|
}
|