mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-11 22:03:15 +00:00
729c1fe656
When flush_cache() is called during boot on our ~7M kernel image, the hundreds of thousands of WATCHDOG_RESET calls end up adding significantly to boottime. Flushing a single cache line doesn't take many microseconds, so doing these calls for every cache line is complete overkill. The generic watchdog_reset() provided by wdt-uclass.c actually contains some rate-limiting logic that should in theory mitigate this, but alas, that rate-limiting must be disabled on powerpc because of its get_timer() implementation - get_timer() works just fine until interrupts are disabled, but it just so happens that the "big" flush_cache() call happens in the part of bootm where interrupts are indeed disabled. [1] [2] [3] I have checked with objdump that the generated code doesn't change when this option is left at its default value of 0: gcc is smart enough to see that the ">=" comparison is tautologically true, hence all assignments to "flushed" are eliminated as dead stores. On our board, setting the option to something like 65536 ends up reducing total boottime by about 0.8 seconds. [1] https://patchwork.ozlabs.org/project/uboot/patch/20200605111657.28773-1-rasmus.villemoes@prevas.dk/ [2] https://lists.denx.de/pipermail/u-boot/2021-April/446906.html [3] https://lists.denx.de/pipermail/u-boot/2021-April/447280.html Reviewed-by: Stefan Roese <sr@denx.de> Signed-off-by: Rasmus Villemoes <rasmus.villemoes@prevas.dk>
46 lines
1.2 KiB
C
46 lines
1.2 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* (C) Copyright 2002
|
|
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <cpu_func.h>
|
|
#include <asm/cache.h>
|
|
#include <watchdog.h>
|
|
|
|
static ulong maybe_watchdog_reset(ulong flushed)
|
|
{
|
|
flushed += CONFIG_SYS_CACHELINE_SIZE;
|
|
if (flushed >= CONFIG_CACHE_FLUSH_WATCHDOG_THRESHOLD) {
|
|
WATCHDOG_RESET();
|
|
flushed = 0;
|
|
}
|
|
return flushed;
|
|
}
|
|
|
|
void flush_cache(ulong start_addr, ulong size)
|
|
{
|
|
ulong addr, start, end;
|
|
ulong flushed = 0;
|
|
|
|
start = start_addr & ~(CONFIG_SYS_CACHELINE_SIZE - 1);
|
|
end = start_addr + size - 1;
|
|
|
|
for (addr = start; (addr <= end) && (addr >= start);
|
|
addr += CONFIG_SYS_CACHELINE_SIZE) {
|
|
asm volatile("dcbst 0,%0" : : "r" (addr) : "memory");
|
|
flushed = maybe_watchdog_reset(flushed);
|
|
}
|
|
/* wait for all dcbst to complete on bus */
|
|
asm volatile("sync" : : : "memory");
|
|
|
|
for (addr = start; (addr <= end) && (addr >= start);
|
|
addr += CONFIG_SYS_CACHELINE_SIZE) {
|
|
asm volatile("icbi 0,%0" : : "r" (addr) : "memory");
|
|
flushed = maybe_watchdog_reset(flushed);
|
|
}
|
|
asm volatile("sync" : : : "memory");
|
|
/* flush prefetch queue */
|
|
asm volatile("isync" : : : "memory");
|
|
}
|