]> git.sur5r.net Git - u-boot/commit
ARC: Flush & invalidate D$ with a single command
authorEugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
Wed, 21 Mar 2018 12:58:50 +0000 (15:58 +0300)
committerAlexey Brodkin <abrodkin@synopsys.com>
Wed, 21 Mar 2018 14:06:49 +0000 (17:06 +0300)
commitc27814be336ee612418ff010f4002deb1cc9c387
tree06a8b7e3e5c18c5d56e916d7edf0055d0aa09744
parent5e0c68edad7d47438721e862fd772710dffca9b4
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>
arch/arc/include/asm/cache.h
arch/arc/lib/cache.c