u-boot/arch/arc/lib
Eugeniy Paltsev c27814be33 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>
2018-03-21 17:06:49 +03:00
..
_millicodethunk.S arc: build libgcc in U-Boot 2015-02-09 16:41:20 +03:00
bootm.c fdt: Implement weak arch_fixup_fdt() 2018-02-18 12:53:38 -07:00
cache.c ARC: Flush & invalidate D$ with a single command 2018-03-21 17:06:49 +03:00
cpu.c board_f: Rename initdram() to dram_init() 2017-04-13 09:40:57 -04:00
init_helpers.c arc: significant cache rework 2015-07-01 17:17:27 +03:00
interrupts.c arc: Update exception & interrupt handling for ARCv2 2016-08-05 12:50:25 +03:00
ints_low.S arc: Update exception & interrupt handling for ARCv2 2016-08-05 12:50:25 +03:00
libgcc2.c arc: build libgcc in U-Boot 2015-02-09 16:41:20 +03:00
libgcc2.h arc: build libgcc in U-Boot 2015-02-09 16:41:20 +03:00
Makefile arc: Get rid of handwritten string routines 2018-03-21 16:21:34 +03:00
relocate.c arc: Introduce a possibility to not relocate U-boot 2018-03-21 16:21:34 +03:00
reset.c arc: move common sources in library 2015-01-15 22:40:49 +03:00
start.S arc: Introduce a possibility to not relocate U-boot 2018-03-21 16:21:34 +03:00