diff options
Diffstat (limited to 'arch/mips/include/asm/pgtable.h')
| -rw-r--r-- | arch/mips/include/asm/pgtable.h | 31 | 
1 files changed, 31 insertions, 0 deletions
diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index 9d8106758142..ae8569475264 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -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  }  |