162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2011 Calxeda, Inc. 462306a36Sopenharmony_ci * Based on PPC version Copyright 2007 MontaVista Software, Inc. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#ifndef ASM_EDAC_H 762306a36Sopenharmony_ci#define ASM_EDAC_H 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci * ECC atomic, DMA, SMP and interrupt safe scrub function. 1062306a36Sopenharmony_ci * Implements the per arch edac_atomic_scrub() that EDAC use for software 1162306a36Sopenharmony_ci * ECC scrubbing. It reads memory and then writes back the original 1262306a36Sopenharmony_ci * value, allowing the hardware to detect and correct memory errors. 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic inline void edac_atomic_scrub(void *va, u32 size) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 6 1862306a36Sopenharmony_ci unsigned int *virt_addr = va; 1962306a36Sopenharmony_ci unsigned int temp, temp2; 2062306a36Sopenharmony_ci unsigned int i; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci for (i = 0; i < size / sizeof(*virt_addr); i++, virt_addr++) { 2362306a36Sopenharmony_ci /* Very carefully read and write to memory atomically 2462306a36Sopenharmony_ci * so we are interrupt, DMA and SMP safe. 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci __asm__ __volatile__("\n" 2762306a36Sopenharmony_ci "1: ldrex %0, [%2]\n" 2862306a36Sopenharmony_ci " strex %1, %0, [%2]\n" 2962306a36Sopenharmony_ci " teq %1, #0\n" 3062306a36Sopenharmony_ci " bne 1b\n" 3162306a36Sopenharmony_ci : "=&r"(temp), "=&r"(temp2) 3262306a36Sopenharmony_ci : "r"(virt_addr) 3362306a36Sopenharmony_ci : "cc"); 3462306a36Sopenharmony_ci } 3562306a36Sopenharmony_ci#endif 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#endif 39