162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef ASM_EDAC_H
362306a36Sopenharmony_ci#define ASM_EDAC_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <asm/compiler.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci/* ECC atomic, DMA, SMP and interrupt safe scrub function */
862306a36Sopenharmony_ci
962306a36Sopenharmony_cistatic inline void edac_atomic_scrub(void *va, u32 size)
1062306a36Sopenharmony_ci{
1162306a36Sopenharmony_ci	unsigned long *virt_addr = va;
1262306a36Sopenharmony_ci	unsigned long temp;
1362306a36Sopenharmony_ci	u32 i;
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci	for (i = 0; i < size / sizeof(unsigned long); i++) {
1662306a36Sopenharmony_ci		/*
1762306a36Sopenharmony_ci		 * Very carefully read and write to memory atomically
1862306a36Sopenharmony_ci		 * so we are interrupt, DMA and SMP safe.
1962306a36Sopenharmony_ci		 *
2062306a36Sopenharmony_ci		 * Intel: asm("lock; addl $0, %0"::"m"(*virt_addr));
2162306a36Sopenharmony_ci		 */
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci		__asm__ __volatile__ (
2462306a36Sopenharmony_ci		"	.set	push					\n"
2562306a36Sopenharmony_ci		"	.set	mips2					\n"
2662306a36Sopenharmony_ci		"1:	ll	%0, %1		# edac_atomic_scrub	\n"
2762306a36Sopenharmony_ci		"	addu	%0, $0					\n"
2862306a36Sopenharmony_ci		"	sc	%0, %1					\n"
2962306a36Sopenharmony_ci		"	beqz	%0, 1b					\n"
3062306a36Sopenharmony_ci		"	.set	pop					\n"
3162306a36Sopenharmony_ci		: "=&r" (temp), "=" GCC_OFF_SMALL_ASM() (*virt_addr)
3262306a36Sopenharmony_ci		: GCC_OFF_SMALL_ASM() (*virt_addr));
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci		virt_addr++;
3562306a36Sopenharmony_ci	}
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#endif
39