Arthur Heymans has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/37196 )
Change subject: [WIP]cpu/x86/cache: CLFLUSH programs to memory before running ......................................................................
[WIP]cpu/x86/cache: CLFLUSH programs to memory before running
When cbmem is initialized in romstage and postcar placed in the stage cache + cbmem where it is run, the assumption is made that this are all in UC memory such that calling invd in postcar is ok.
For performance reasons (e.g. postcar decompression) it is desirable to cache cbmem and the stage cache during romstage. Another reason is that AGESA sets up MTRR during romstage to cache all dram, which is currently worked around by using additional MTRR to make that UC.
TODO be nice to reviewers and spit some parts off.
UNTESTED
Change-Id: I7ff2a57aee620908b71829457ea0f5a0c410ec5b Signed-off-by: Arthur Heymans arthur@aheymans.xyz --- M src/arch/x86/postcar_loader.c M src/cpu/x86/cache/Makefile.inc M src/cpu/x86/cache/cache.c M src/include/cpu/x86/cache.h 4 files changed, 68 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/96/37196/1
diff --git a/src/arch/x86/postcar_loader.c b/src/arch/x86/postcar_loader.c index b53cbf8..53ab4f9 100644 --- a/src/arch/x86/postcar_loader.c +++ b/src/arch/x86/postcar_loader.c @@ -208,6 +208,21 @@ MTRR_TYPE_WRBACK); }
+/* + * POSTCAR will call invd so don't make assumptions on cbmem + * and external stage cache being UC. + */ +static void postcar_flush_cache(void) +{ + uintptr_t stage_cache_base; + size_t stage_cache_size; + prog_segment_loaded((uintptr_t)cbmem_top(), cbmem_overhead_size(), SEG_FINAL); + if (CONFIG(TSEG_STAGE_CACHE)) { + stage_cache_external_region((void **)&stage_cache_base, &stage_cache_size); + prog_segment_loaded(stage_cache_base, stage_cache_size, SEG_FINAL); + } +} + void run_postcar_phase(struct postcar_frame *pcf) { struct prog prog = @@ -222,8 +237,10 @@ parameters between S3 resume and normal boot. On the platforms where the values are the same it's a nop. */ finalize_load(prog.arg, pcf->stack); - } else + } else { load_postcar_cbfs(&prog, pcf); + postcar_flush_cache(); + }
/* As postcar exist, it's end of romstage here */ timestamp_add_now(TS_END_ROMSTAGE); diff --git a/src/cpu/x86/cache/Makefile.inc b/src/cpu/x86/cache/Makefile.inc index b33b9ee..759488e 100644 --- a/src/cpu/x86/cache/Makefile.inc +++ b/src/cpu/x86/cache/Makefile.inc @@ -1 +1,2 @@ +romstage-y += cache.c ramstage-y += cache.c diff --git a/src/cpu/x86/cache/cache.c b/src/cpu/x86/cache/cache.c index 2313c4d..ac2c45b 100644 --- a/src/cpu/x86/cache/cache.c +++ b/src/cpu/x86/cache/cache.c @@ -11,8 +11,11 @@ * GNU General Public License for more details. */
+#include <cbmem.h> +#include <program_loading.h> #include <console/console.h> #include <cpu/x86/cache.h> +#include <arch/cpu.h>
void x86_enable_cache(void) { @@ -20,3 +23,47 @@ printk(BIOS_INFO, "Enabling cache\n"); enable_cache(); } + +int clflush_supported(void) +{ + return (cpuid_edx(1) >> 19) & 1; +} + +static void clflush_region(uintptr_t start, size_t size) +{ + uintptr_t addr; + size_t cl_size = (cpuid_ebx(1) >> 8) & 0xff; + if (!clflush_supported()) + return; + for (addr = (start / cl_size) * cl_size; addr < start + size; addr += cl_size) + clflush((void *)addr); +} + +static int dram_ready; + +/* + * For each segment of a program loaded this function is called + * to invalidate caches for the addresses of the loaded segment + */ +void arch_segment_loaded(uintptr_t start, size_t size, int flags) +{ + /* INVD is only called in postcar stage so we only need + to make sure that our things hit dram during romstage. */ + if (!ENV_ROMSTAGE) + return; + if (flags != SEG_FINAL) + return; + if (!dram_ready) + return; + + if (!clflush_supported()) + printk(BIOS_DEBUG, "Not flushing cache to ram, CLFLUSH not supported\n"); + clflush_region(start, size); +} + +static void set_dram_ready(int unused) +{ + dram_ready = 1; +} + +ROMSTAGE_CBMEM_INIT_HOOK(set_dram_ready); diff --git a/src/include/cpu/x86/cache.h b/src/include/cpu/x86/cache.h index 713ca32..2d2727f 100644 --- a/src/include/cpu/x86/cache.h +++ b/src/include/cpu/x86/cache.h @@ -55,6 +55,8 @@ asm volatile ("clflush (%0)"::"r" (addr)); }
+int clflush_supported(void); + /* The following functions require the __always_inline due to AMD * function STOP_CAR_AND_CPU that disables cache as * RAM, the cache as RAM stack can no longer be used. Called