summaryrefslogtreecommitdiff
path: root/arch/arc/include
diff options
context:
space:
mode:
authorEugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>2018-03-21 15:58:50 +0300
committerAlexey Brodkin <abrodkin@synopsys.com>2018-03-21 17:06:49 +0300
commitc27814be336ee612418ff010f4002deb1cc9c387 (patch)
tree06a8b7e3e5c18c5d56e916d7edf0055d0aa09744 /arch/arc/include
parent5e0c68edad7d47438721e862fd772710dffca9b4 (diff)
downloadu-boot-c27814be336ee612418ff010f4002deb1cc9c387.tar.xz
ARC: Flush & invalidate D$ with a single command
We don't implement separate flush_dcache_all() intentionally as entire data cache invalidation is dangerous operation even if we flush data cache right before invalidation. There is the real example: We may get stuck in the following code if we store any context (like BLINK register) on stack in invalidate_dcache_all() function. BLINK register is the register where return address is automatically saved when we do function call with instructions like 'bl'. void flush_dcache_all() { __dc_entire_op(OP_FLUSH); // Other code // } void invalidate_dcache_all() { __dc_entire_op(OP_INV); // Other code // } void foo(void) { flush_dcache_all(); invalidate_dcache_all(); } Now let's see what really happens during that code execution: foo() |->> call flush_dcache_all [return address is saved to BLINK register] [push BLINK] (save to stack) ![point 1] |->> call __dc_entire_op(OP_FLUSH) [return address is saved to BLINK register] [flush L1 D$] return [jump to BLINK] <<------ [other flush_dcache_all code] [pop BLINK] (get from stack) return [jump to BLINK] <<------ |->> call invalidate_dcache_all [return address is saved to BLINK register] [push BLINK] (save to stack) ![point 2] |->> call __dc_entire_op(OP_FLUSH) [return address is saved to BLINK register] [invalidate L1 D$] ![point 3] // Oops!!! // We lose return address from invalidate_dcache_all function: // we save it to stack and invalidate L1 D$ after that! return [jump to BLINK] <<------ [other invalidate_dcache_all code] [pop BLINK] (get from stack) // we don't have this data in L1 dcache as we invalidated it in [point 3] // so we get it from next memory level (for example DDR memory) // but in the memory we have value which we save in [point 1], which // is return address from flush_dcache_all function (instead of // address from current invalidate_dcache_all function which we // saved in [point 2] !) return [jump to BLINK] <<------ // As BLINK points to invalidate_dcache_all, we call it again and // loop forever. Fortunately we may do flush and invalidation of D$ with a single one instruction which automatically mitigates a situation described above. And because invalidate_dcache_all() isn't used in common U-Boot code we implement "flush and invalidate dcache all" instead. Signed-off-by: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
Diffstat (limited to 'arch/arc/include')
-rw-r--r--arch/arc/include/asm/cache.h1
1 files changed, 1 insertions, 0 deletions
diff --git a/arch/arc/include/asm/cache.h b/arch/arc/include/asm/cache.h
index d26d9fb18d..382c4126c3 100644
--- a/arch/arc/include/asm/cache.h
+++ b/arch/arc/include/asm/cache.h
@@ -30,6 +30,7 @@
#ifndef __ASSEMBLY__
void cache_init(void);
+void flush_n_invalidate_dcache_all(void);
#endif /* __ASSEMBLY__ */