On 10/24/2016 04:44 AM, Mark Rutland wrote:
Hi,
Sorry for joining this a bit late; apologies if the below re-treads
ground already covered.
On Wed, Oct 19, 2016 at 09:25:02AM -0600, Stephen Warren wrote:
On 10/14/2016 02:17 PM, York Sun wrote:
Current code turns off d-cache first, then flush all levels of cache.
This results data loss. As soon as d-cache is off, the dirty cache
is discarded according to the test on LS2080A. This issue was not
seen as long as external L3 cache was flushed to push the data to
main memory. However, external L3 cache is not guaranteed to have
the data. To fix this, flush the d-cache by way/set first to make
sure cache is clean before turning it off.
diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c
@@ -478,9 +478,9 @@ void dcache_disable(void)
+ flush_dcache_all();
set_sctlr(sctlr & ~(CR_C|CR_M));
- flush_dcache_all();
__asm_invalidate_tlb_all();
I talked to Mark Rutland at ARM, and I believe the current code is
correct.
Well, almost, but not quite. It's a long story... ;)
To be clear, I was referring specifically/only to the relative ordering
of the call to flush_dcache_all() and the SCTLR register modification,
rather than wider aspects of the code:-)
I gave a primer [1,2] on the details at ELC earlier this year, which may
or may not be useful.
The big details are:
* Generaly "Flush" is ambiguous/meaningless. Here you seem to want
clean+invalidate.
Yes. I think the naming of this code is driven by U-Boot's
cross-architecture compatibility and history, hence why it doesn't use
the expected ARM terminology.
* Set/Way operations are for IMPLEMENTATION DEFINED (i.e. SoC-specific)
cache maintenance sequences, and are not truly portable (e.g. not
affecting system caches).
I assume that an earlier boot stage initialised the caches prior to
U-Boot. Given that, you *only* need to perform maintenance for the
memory you have (at any point) mapped with cacheable attrbiutes, which
should be a small subset of the PA space. With ARMv8-A, broadcast
maintenance to the PoC should affect all relevant caches (assuming you
use the correct shareability attributes).
There is another thread (or fork of this thread) where York suggests
replacing this code with operations by VA instead.
* You *cannot* write a dcache disable routine in C, as the compiler can
perform a number of implicit memory accesses (e.g. stack, globals,
GOT). For that alone, I do not believe the code above is correct.
Note that we have seen this being an issue in practice, before we got
rid of Set/Way ops from arm64 Linux (see commit 5e051531447259e5).
I agree. In practice, at least with the compiler I happen to be using,
we are currently getting lucky and there aren't any RAM accesses emitted
by the compiler in this part of the code. Admittedly that won't hold
true for everyone or across all of time though, so this should certainly
be fixed...
* Your dcache disable code *must* be clean to the PoC, prior to
execution, or instruction fetches could see stale data. You can first
*clean* this to the PoC, which is sufficient to avoid the problems
above.
I'm not sure if we have any documented rules/assumptions regarding
cache/... state upon U-Boot entry like the Linux kernel does. It would
probably be a good idea to do so...
I believe that for this particular piece of code, since it's always
executed late in U-Boot's operation, the requirement is covered by
U-Boot's code relocation routine, since that memcpy()s' .text/.data to
the top of usable RAM, and hence hopefully is already fully cleaning the
dcache and invalidating the icache afterwards.
* The SCTLR_ELx.{C,I} bits do not enable/disable caches; they merely
activate/deactiveate cacheable attributes on data/instruction fetches.
Note that cacheable instruction fetches can allocate into unified/data
caches.
Also, note that the I bit is independent of the C bit, and the
attributes it provides differ when the M bit is clear. Generally, I
would advise that at all times M == C == I, as that leads to the least
surprise.
I think M==C==I is generally true in U-Boot, except for a limited time
right before it jumps to the OS, where icache and dcache "are
disabled"[1] separately, but one right after the other.
[1] to abuse the terminology that you pointed out was incorrect:-)
Thanks,
Mark.
[1] http://events.linuxfoundation.org/sites/events/files/slides/slides_17.pdf
[2] https://www.youtube.com/watch?v=F0SlIMHRnLk
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot