Lin Huang (hl(a)rock-chips.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/13914
-gerrit
commit 4ef157d50a6b87b5e69e62558633d7ead18be5c6
Author: huang lin <hl(a)rock-chips.com>
Date: Thu Mar 3 15:29:34 2016 +0800
libpayload: mmu: Assuming that memory 0-4GiB is device memory
in some platform(like rk3399), mmio space start 0xf8000000, exceed
2GB, so fix it.
Change-Id: I39da4ce247422f67451711ac0ed5a5e1119ed836
Signed-off-by: huang lin <hl(a)rock-chips.com>
---
payloads/libpayload/arch/arm64/mmu.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/payloads/libpayload/arch/arm64/mmu.c b/payloads/libpayload/arch/arm64/mmu.c
index f07e4c4..9bb402b 100644
--- a/payloads/libpayload/arch/arm64/mmu.c
+++ b/payloads/libpayload/arch/arm64/mmu.c
@@ -260,7 +260,7 @@ void mmu_config_range(void *start, size_t size, uint64_t tag)
* Desc : Initialize mmu based on the mmu_memrange passed. ttb_buffer is used as
* the base address for xlat tables. TTB_DEFAULT_SIZE defines the max number of
* tables that can be used
- * Assuming that memory 0-2GiB is device memory.
+ * Assuming that memory 0-4GiB is device memory.
*/
uint64_t mmu_init(struct mmu_ranges *mmu_ranges)
{
@@ -275,8 +275,7 @@ uint64_t mmu_init(struct mmu_ranges *mmu_ranges)
printf("Libpayload ARM64: TTB_BUFFER: 0x%p Max Tables: %d\n",
(void*)xlat_addr, max_tables);
- mmu_config_range(NULL, 0x80000000, TYPE_DEV_MEM);
-
+ mmu_config_range(NULL, 0x100000000, TYPE_DEV_MEM);
for (; i < mmu_ranges->used; i++)
mmu_config_range((void *)mmu_ranges->entries[i].base,
mmu_ranges->entries[i].size,
Andrey Petrov (andrey.petrov(a)intel.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/13364
-gerrit
commit 99f8bf54b8223eb83407e9ab4f1acc3f3e62ac6e
Author: Alexandru Gagniuc <alexandrux.gagniuc(a)intel.com>
Date: Thu Mar 10 15:02:02 2016 -0800
soc/apollolake: Tear down cache-as-ram very early in ramstage
Because of the reasons explained in the file, teardown of CAR needs to
be done in ramstage. This patch addresses that issues in a way
designed to minimize boot time.
Change-Id: I6a0cb07f5b35ad42537da688e376ac96612990a6
Signed-off-by: Alexandru Gagniuc <alexandrux.gagniuc(a)intel.com>
Signed-off-by: Andrey Petrov <andrey.petrov(a)intel.com>
---
src/soc/intel/apollolake/Makefile.inc | 1 +
src/soc/intel/apollolake/bootblock/cache_as_ram.S | 7 +-
src/soc/intel/apollolake/car_teardown.c | 135 ++++++++++++++++++++++
src/soc/intel/apollolake/include/soc/cpu.h | 7 +-
4 files changed, 144 insertions(+), 6 deletions(-)
diff --git a/src/soc/intel/apollolake/Makefile.inc b/src/soc/intel/apollolake/Makefile.inc
index 4e05726..6bbfe57 100644
--- a/src/soc/intel/apollolake/Makefile.inc
+++ b/src/soc/intel/apollolake/Makefile.inc
@@ -25,6 +25,7 @@ romstage-y += memmap.c
romstage-y += mmap_boot.c
smm-y += placeholders.c
+ramstage-y += car_teardown.c
ramstage-y += cpu.c
ramstage-y += chip.c
ramstage-y += placeholders.c
diff --git a/src/soc/intel/apollolake/bootblock/cache_as_ram.S b/src/soc/intel/apollolake/bootblock/cache_as_ram.S
index c81fe0a..cc021dc 100644
--- a/src/soc/intel/apollolake/bootblock/cache_as_ram.S
+++ b/src/soc/intel/apollolake/bootblock/cache_as_ram.S
@@ -16,8 +16,7 @@
#include <cpu/x86/cache.h>
#include <cpu/x86/cr.h>
#include <cpu/x86/post_code.h>
-
-#define EVICT_CTL_MSR 0x2e0
+#include <soc/cpu.h>
.global bootblock_pre_c_entry
bootblock_pre_c_entry:
@@ -96,7 +95,7 @@ clear_var_mtrr:
mov %eax, %cr0
/* Disable cache eviction (setup stage) */
- mov $EVICT_CTL_MSR, %ecx
+ mov $MSR_EVICT_CTL, %ecx
rdmsr
or $0x1, %eax
wrmsr
@@ -112,7 +111,7 @@ clear_var_mtrr:
post_code(0x27)
/* Disable cache eviction (run stage) */
- mov $EVICT_CTL_MSR, %ecx
+ mov $MSR_EVICT_CTL, %ecx
rdmsr
or $0x2, %eax
wrmsr
diff --git a/src/soc/intel/apollolake/car_teardown.c b/src/soc/intel/apollolake/car_teardown.c
new file mode 100644
index 0000000..77d0dd4
--- /dev/null
+++ b/src/soc/intel/apollolake/car_teardown.c
@@ -0,0 +1,135 @@
+/*
+ * Cache-as-ram teardown for apollolake SOC. See detailed explanation below.
+ *
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2015 Intel Corp.
+ * (Written by Alexandru Gagniuc <alexandrux.gagniuc(a)intel.com> for Intel Corp.)
+ * (Written by Andrey Petrov <andrey.petrov(a)intel.com> for Intel Corp.)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <bootstate.h>
+#include <console/console.h>
+#include <cpu/cpu.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/mtrr.h>
+#include <cpu/x86/msr.h>
+#include <cpu/x86/tsc.h>
+#include <cbmem.h>
+#include <memrange.h>
+#include <soc/cpu.h>
+#include <symbols.h>
+
+#define CACHELINE_SIZE 64
+/*
+ * The CAR teardown on apollolake is more complicated than the standard x86
+ * teardown paths because romstage executes in CAR. That means romstage cannot
+ * do the teardown. For performance reasons, the cache is also used as a backing
+ * store for RAM after raminit.
+ *
+ * This results in a cache with both a CAR region, and memory-backed regions:
+ * - Invalidating the entire cache will evict stack and code that has not yet
+ * been commited, to RAM, resulting in a crash.
+ * - A 'wbinvd' will result in a crash during the write-back phase because
+ * the CAR region has no backing store.
+ *
+ * This teardown path resolves these problems by first flushing important data
+ * out of cache, to memory. After this operation, it is safe to invalidate the
+ * entire cache, which is then followed by standard MTRR housekeeping.
+ *
+ * For performance reasons, only the memory regions which may have been written
+ * to are flushed. This includes ramstage code and cbmem. A complete flush of
+ * all RAM ranges would take several seconds.
+ */
+
+static void clflush(uintptr_t addr)
+{
+ __asm__ volatile ("clflush (%0)"::"r" (addr));
+}
+
+static void clflush_mem_range(uintptr_t start, uintptr_t end)
+{
+ end = ALIGN_UP(end, CACHELINE_SIZE);
+
+ for (start = ALIGN_DOWN(start, CACHELINE_SIZE); start < end;
+ start += CACHELINE_SIZE)
+ clflush(start);
+}
+
+static void flush_ram_cache_and_invalidate(void)
+{
+ uintptr_t cbmem_base;
+ size_t cbmem_size;
+ struct memranges ctx;
+ struct range_entry entries[3];
+ const struct range_entry *r;
+ const struct cbmem_entry *fsp_rsvd_mem;
+
+ memranges_init_empty(&ctx, entries, ARRAY_SIZE(entries));
+
+ /* Figure out where ramstage resides; this is inclusive of the stack */
+ memranges_insert(&ctx, (uintptr_t)&_program, _program_size, 0);
+
+ /* It's okay if CBMEM and ramstage overlap. */
+ cbmem_region_used(&cbmem_base, &cbmem_size);
+ memranges_insert(&ctx, cbmem_base, cbmem_size, 0);
+
+ /*
+ * FSP reserved memory was written before caching was enabled. Thus it
+ * does not need to be flushed. This saves about 10ms of boot time.
+ */
+ fsp_rsvd_mem = cbmem_entry_find(CBMEM_ID_FSP_RESERVED_MEMORY);
+ if (fsp_rsvd_mem) {
+ memranges_create_hole(&ctx,
+ (uintptr_t)cbmem_entry_start(fsp_rsvd_mem),
+ cbmem_entry_size(fsp_rsvd_mem)
+ );
+ }
+
+ /* Flush ramstage code and stack */
+ memranges_each_entry(r, &ctx)
+ clflush_mem_range(range_entry_base(r), range_entry_end(r));
+
+ /* Now that important data is flushed, invalidate all caches */
+ invd();
+}
+
+static void disable_car_region_and_no_evict_mode(void)
+{
+ msr_t msr;
+
+ /* Disable variable and fixed MTRRs */
+ msr.lo = msr.hi = 0;
+ wrmsr(MTRR_DEF_TYPE_MSR, msr);
+ /* Disable CAR MTRR */
+ wrmsr(MTRR_PHYS_BASE(0), msr);
+ wrmsr(MTRR_PHYS_MASK(0), msr);
+
+ /* Switch out of "no evict" mode */
+ msr = rdmsr(MSR_EVICT_CTL);
+ msr.lo &= ~2;
+ wrmsr(MSR_EVICT_CTL, msr);
+
+ msr.lo &= ~1;
+ wrmsr(MSR_EVICT_CTL, msr);
+
+ /* Re-enable remaining MTRRs */
+ msr.lo = MTRR_DEF_TYPE_EN;
+ msr.hi = 0;
+ wrmsr(MTRR_DEF_TYPE_MSR, msr);
+}
+
+static void tear_down_car(void *unused_arg)
+{
+ (void) unused_arg;
+
+ flush_ram_cache_and_invalidate();
+ disable_car_region_and_no_evict_mode();
+}
+
+BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_ENTRY, tear_down_car, NULL);
diff --git a/src/soc/intel/apollolake/include/soc/cpu.h b/src/soc/intel/apollolake/include/soc/cpu.h
index 765be70..b7b2fcc 100644
--- a/src/soc/intel/apollolake/include/soc/cpu.h
+++ b/src/soc/intel/apollolake/include/soc/cpu.h
@@ -13,19 +13,22 @@
#ifndef _SOC_APOLLOLAKE_CPU_H_
#define _SOC_APOLLOLAKE_CPU_H_
+#ifndef __ASSEMBLER__
#include <cpu/x86/msr.h>
#include <device/device.h>
+void apollolake_init_cpus(struct device *dev);
+#endif
+
#define CPUID_APOLLOLAKE_A0 0x506c8
#define CPUID_APOLLOLAKE_B0 0x506c9
#define MSR_PLATFORM_INFO 0xce
#define MSR_POWER_MISC 0x120
#define MSR_CORE_THREAD_COUNT 0x35
+#define MSR_EVICT_CTL 0x2e0
#define BASE_CLOCK_MHZ 100
-void apollolake_init_cpus(struct device *dev);
-
#endif /* _SOC_APOLLOLAKE_CPU_H_ */
Andrey Petrov (andrey.petrov(a)intel.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/13364
-gerrit
commit 13f1a32a6ead5f5045c79936713e5206af8e8e0c
Author: Alexandru Gagniuc <alexandrux.gagniuc(a)intel.com>
Date: Thu Mar 10 15:02:02 2016 -0800
soc/apollolake: Tear down cache-as-ram very early in ramstage
Because of the reasons explained in the file, teardown of CAR needs to
be done in ramstage. This patch addresses that issues in a way
designed to minimize boot time.
Change-Id: I6a0cb07f5b35ad42537da688e376ac96612990a6
Signed-off-by: Alexandru Gagniuc <alexandrux.gagniuc(a)intel.com>
Signed-off-by: Andrey Petrov <andrey.petrov(a)intel.com>
---
src/soc/intel/apollolake/Makefile.inc | 1 +
src/soc/intel/apollolake/bootblock/cache_as_ram.S | 7 +-
src/soc/intel/apollolake/car_teardown.c | 134 ++++++++++++++++++++++
src/soc/intel/apollolake/include/soc/cpu.h | 7 +-
4 files changed, 143 insertions(+), 6 deletions(-)
diff --git a/src/soc/intel/apollolake/Makefile.inc b/src/soc/intel/apollolake/Makefile.inc
index 4e05726..6bbfe57 100644
--- a/src/soc/intel/apollolake/Makefile.inc
+++ b/src/soc/intel/apollolake/Makefile.inc
@@ -25,6 +25,7 @@ romstage-y += memmap.c
romstage-y += mmap_boot.c
smm-y += placeholders.c
+ramstage-y += car_teardown.c
ramstage-y += cpu.c
ramstage-y += chip.c
ramstage-y += placeholders.c
diff --git a/src/soc/intel/apollolake/bootblock/cache_as_ram.S b/src/soc/intel/apollolake/bootblock/cache_as_ram.S
index c81fe0a..cc021dc 100644
--- a/src/soc/intel/apollolake/bootblock/cache_as_ram.S
+++ b/src/soc/intel/apollolake/bootblock/cache_as_ram.S
@@ -16,8 +16,7 @@
#include <cpu/x86/cache.h>
#include <cpu/x86/cr.h>
#include <cpu/x86/post_code.h>
-
-#define EVICT_CTL_MSR 0x2e0
+#include <soc/cpu.h>
.global bootblock_pre_c_entry
bootblock_pre_c_entry:
@@ -96,7 +95,7 @@ clear_var_mtrr:
mov %eax, %cr0
/* Disable cache eviction (setup stage) */
- mov $EVICT_CTL_MSR, %ecx
+ mov $MSR_EVICT_CTL, %ecx
rdmsr
or $0x1, %eax
wrmsr
@@ -112,7 +111,7 @@ clear_var_mtrr:
post_code(0x27)
/* Disable cache eviction (run stage) */
- mov $EVICT_CTL_MSR, %ecx
+ mov $MSR_EVICT_CTL, %ecx
rdmsr
or $0x2, %eax
wrmsr
diff --git a/src/soc/intel/apollolake/car_teardown.c b/src/soc/intel/apollolake/car_teardown.c
new file mode 100644
index 0000000..b866443
--- /dev/null
+++ b/src/soc/intel/apollolake/car_teardown.c
@@ -0,0 +1,134 @@
+/*
+ * Cache-as-ram teardown for apollolake SOC. See detailed explanation below.
+ *
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2015 Intel Corp.
+ * (Written by Alexandru Gagniuc <alexandrux.gagniuc(a)intel.com> for Intel Corp.)
+ * (Written by Andrey Petrov <andrey.petrov(a)intel.com> for Intel Corp.)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <bootstate.h>
+#include <console/console.h>
+#include <cpu/cpu.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/mtrr.h>
+#include <cpu/x86/msr.h>
+#include <cpu/x86/tsc.h>
+#include <cbmem.h>
+#include <memrange.h>
+#include <symbols.h>
+
+#define CACHELINE_SIZE 64
+/*
+ * The CAR teardown on apollolake is more complicated than the standard x86
+ * teardown paths because romstage executes in CAR. That means romstage cannot
+ * do the teardown. For performance reasons, the cache is also used as a backing
+ * store for RAM after raminit.
+ *
+ * This results in a cache with both a CAR region, and memory-backed regions:
+ * - Invalidating the entire cache will evict stack and code that has not yet
+ * been commited, to RAM, resulting in a crash.
+ * - A 'wbinvd' will result in a crash during the write-back phase because
+ * the CAR region has no backing store.
+ *
+ * This teardown path resolves these problems by first flushing important data
+ * out of cache, to memory. After this operation, it is safe to invalidate the
+ * entire cache, which is then followed by standard MTRR housekeeping.
+ *
+ * For performance reasons, only the memory regions which may have been written
+ * to are flushed. This includes ramstage code and cbmem. A complete flush of
+ * all RAM ranges would take several seconds.
+ */
+
+static void clflush(uintptr_t addr)
+{
+ __asm__ volatile ("clflush (%0)"::"r" (addr));
+}
+
+static void clflush_mem_range(uintptr_t start, uintptr_t end)
+{
+ end = ALIGN_UP(end, CACHELINE_SIZE);
+
+ for (start = ALIGN_DOWN(start, CACHELINE_SIZE); start < end;
+ start += CACHELINE_SIZE)
+ clflush(start);
+}
+
+static void flush_ram_cache_and_invalidate(void)
+{
+ uintptr_t cbmem_base;
+ size_t cbmem_size;
+ struct memranges ctx;
+ struct range_entry entries[3];
+ const struct range_entry *r;
+ const struct cbmem_entry *fsp_rsvd_mem;
+
+ memranges_init_empty(&ctx, entries, ARRAY_SIZE(entries));
+
+ /* Figure out where ramstage resides; this is inclusive of the stack */
+ memranges_insert(&ctx, (uintptr_t)&_program, _program_size, 0);
+
+ /* It's okay if CBMEM and ramstage overlap. */
+ cbmem_region_used(&cbmem_base, &cbmem_size);
+ memranges_insert(&ctx, cbmem_base, cbmem_size, 0);
+
+ /*
+ * FSP reserved memory was written before caching was enabled. Thus it
+ * does not need to be flushed. This saves about 10ms of boot time.
+ */
+ fsp_rsvd_mem = cbmem_entry_find(CBMEM_ID_FSP_RESERVED_MEMORY);
+ if (fsp_rsvd_mem) {
+ memranges_create_hole(&ctx,
+ (uintptr_t)cbmem_entry_start(fsp_rsvd_mem),
+ cbmem_entry_size(fsp_rsvd_mem)
+ );
+ }
+
+ /* Flush ramstage code and stack */
+ memranges_each_entry(r, &ctx)
+ clflush_mem_range(range_entry_base(r), range_entry_end(r));
+
+ /* Now that important data is flushed, invalidate all caches */
+ invd();
+}
+
+static void disable_car_region_and_no_evict_mode(void)
+{
+ msr_t msr;
+
+ /* Disable variable and fixed MTRRs */
+ msr.lo = msr.hi = 0;
+ wrmsr(MTRR_DEF_TYPE_MSR, msr);
+ /* Disable CAR MTRR */
+ wrmsr(MTRR_PHYS_BASE(0), msr);
+ wrmsr(MTRR_PHYS_MASK(0), msr);
+
+ /* Switch out of "no evict" mode */
+ msr = rdmsr(MSR_EVICT_CTL);
+ msr.lo &= ~2;
+ wrmsr(MSR_EVICT_CTL, msr);
+
+ msr.lo &= ~1;
+ wrmsr(MSR_EVICT_CTL, msr);
+
+ /* Re-enable remaining MTRRs */
+ msr.lo = MTRR_DEF_TYPE_EN;
+ msr.hi = 0;
+ wrmsr(MTRR_DEF_TYPE_MSR, msr);
+}
+
+static void tear_down_car(void *unused_arg)
+{
+ (void) unused_arg;
+
+ flush_ram_cache_and_invalidate();
+ disable_car_region_and_no_evict_mode();
+}
+
+BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_ENTRY, tear_down_car, NULL);
diff --git a/src/soc/intel/apollolake/include/soc/cpu.h b/src/soc/intel/apollolake/include/soc/cpu.h
index 765be70..b7b2fcc 100644
--- a/src/soc/intel/apollolake/include/soc/cpu.h
+++ b/src/soc/intel/apollolake/include/soc/cpu.h
@@ -13,19 +13,22 @@
#ifndef _SOC_APOLLOLAKE_CPU_H_
#define _SOC_APOLLOLAKE_CPU_H_
+#ifndef __ASSEMBLER__
#include <cpu/x86/msr.h>
#include <device/device.h>
+void apollolake_init_cpus(struct device *dev);
+#endif
+
#define CPUID_APOLLOLAKE_A0 0x506c8
#define CPUID_APOLLOLAKE_B0 0x506c9
#define MSR_PLATFORM_INFO 0xce
#define MSR_POWER_MISC 0x120
#define MSR_CORE_THREAD_COUNT 0x35
+#define MSR_EVICT_CTL 0x2e0
#define BASE_CLOCK_MHZ 100
-void apollolake_init_cpus(struct device *dev);
-
#endif /* _SOC_APOLLOLAKE_CPU_H_ */
Andrey Petrov (andrey.petrov(a)intel.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/14095
-gerrit
commit c400cdcb9d8db3598b164482b681d72bd8a1337b
Author: Andrey Petrov <andrey.petrov(a)intel.com>
Date: Sun Mar 13 16:01:55 2016 -0700
soc/intel/apollolake: enable RAM cache for cbmem region in ramstage
Since ramstage code as well as FSP code is run in cbmem that is
placed in DRAM, it is imporant to have that region cached for
performance reasons. This patch enables WB cache for 16MiB below
cbmem top which is a safe bet ramstage is covered.
Change-Id: I3f2f6e82f3b9060c7350ddff754cd3dbcf457671
Signed-off-by: Andrey Petrov <andrey.petrov(a)intel.com>
---
src/soc/intel/apollolake/romstage.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/src/soc/intel/apollolake/romstage.c b/src/soc/intel/apollolake/romstage.c
index 7c8924d..45899fd 100644
--- a/src/soc/intel/apollolake/romstage.c
+++ b/src/soc/intel/apollolake/romstage.c
@@ -15,6 +15,7 @@
#include <arch/symbols.h>
#include <cbfs.h>
#include <cbmem.h>
+#include <cpu/x86/mtrr.h>
#include <console/console.h>
#include <device/pci_def.h>
#include <fsp/api.h>
@@ -80,6 +81,7 @@ asmlinkage void car_stage_entry(void)
void *hob_list_ptr;
struct range_entry fsp_mem;
struct range_entry reg_car;
+ uintptr_t top_of_ram;
printk(BIOS_DEBUG, "Starting romstage...\n");
@@ -95,6 +97,24 @@ asmlinkage void car_stage_entry(void)
die("FSP memory init failed. Giving up.");
}
+ /*
+ * Cache 16 MiB area right below cbmem, so that ramstage and FSP
+ * reserved memory ran cached. This assumes address is at least
+ * 16 MiB aligned.
+ *
+ * After this call we get:
+ * - Non-evict mode (NEM) is enabled
+ * - Write-back cache is active for small window in DRAM
+ *
+ * Since NEM mode blocks cache fills, memory operations do not make
+ * it into L2 cache. L1D cache however works in normal mode. Since
+ * L1 size is smaller than the actual working set, we are slower than
+ * fully fledged L2. However it is still about 10x faster than non-
+ * cached memory.
+ */
+ top_of_ram = (uintptr_t) cbmem_top();
+ set_var_mtrr(1, top_of_ram - 16 * MiB, 16 * MiB, MTRR_TYPE_WRBACK);
+
fsp_find_reserved_memory(&fsp_mem, hob_list_ptr);
/* initialize cbmem by adding FSP reserved memory first thing */
Andrey Petrov (andrey.petrov(a)intel.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/14095
-gerrit
commit cecad57bcadecf45ae46b73f5ae6dab21aca01fd
Author: Andrey Petrov <andrey.petrov(a)intel.com>
Date: Sun Mar 13 16:01:55 2016 -0700
soc/intel/apollolake: enable WB cache for cbmem region in romstage
Since ramstage is run in cbmem that is placed in DRAM, it is imporant
to have that region cached. This patch tries to cache 8MiB right below
cbmem_top which is a safe bet ramstage is covered.
Change-Id: I3f2f6e82f3b9060c7350ddff754cd3dbcf457671
Signed-off-by: Andrey Petrov <andrey.petrov(a)intel.com>
---
src/soc/intel/apollolake/romstage.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/src/soc/intel/apollolake/romstage.c b/src/soc/intel/apollolake/romstage.c
index 7c8924d..159535c 100644
--- a/src/soc/intel/apollolake/romstage.c
+++ b/src/soc/intel/apollolake/romstage.c
@@ -15,6 +15,7 @@
#include <arch/symbols.h>
#include <cbfs.h>
#include <cbmem.h>
+#include <cpu/x86/mtrr.h>
#include <console/console.h>
#include <device/pci_def.h>
#include <fsp/api.h>
@@ -80,6 +81,7 @@ asmlinkage void car_stage_entry(void)
void *hob_list_ptr;
struct range_entry fsp_mem;
struct range_entry reg_car;
+ uintptr_t top_of_ram;
printk(BIOS_DEBUG, "Starting romstage...\n");
@@ -95,6 +97,14 @@ asmlinkage void car_stage_entry(void)
die("FSP memory init failed. Giving up.");
}
+ /*
+ * Cache 16 MiB area right below cbmem, so that ramstage will be
+ * decompressed and ran from cached memory. This assumes address
+ * is at least 16 MiB aligned.
+ */
+ top_of_ram = (uintptr_t) cbmem_top();
+ set_var_mtrr(1, top_of_ram - 16 * MiB, 16 * MiB, MTRR_TYPE_WRBACK);
+
fsp_find_reserved_memory(&fsp_mem, hob_list_ptr);
/* initialize cbmem by adding FSP reserved memory first thing */
Andrey Petrov (andrey.petrov(a)intel.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/13364
-gerrit
commit efd91b5651a9af3fdd072d8f987f3fa2c87060a9
Author: Alexandru Gagniuc <alexandrux.gagniuc(a)intel.com>
Date: Thu Mar 10 15:02:02 2016 -0800
soc/apollolake: Tear down cache-as-ram very early in ramstage
Because of the reasons explained in the file, teardown of CAR needs to
be done in ramstage. This patch addresses that issues in a way
designed to minimize boot time. Teardown currently takes about 7 ms.
Change-Id: I6a0cb07f5b35ad42537da688e376ac96612990a6
Signed-off-by: Alexandru Gagniuc <alexandrux.gagniuc(a)intel.com>
Signed-off-by: Andrey Petrov <andrey.petrov(a)intel.com>
---
src/soc/intel/apollolake/Makefile.inc | 1 +
src/soc/intel/apollolake/bootblock/cache_as_ram.S | 7 +-
src/soc/intel/apollolake/car_teardown.c | 135 ++++++++++++++++++++++
src/soc/intel/apollolake/include/soc/cpu.h | 7 +-
4 files changed, 144 insertions(+), 6 deletions(-)
diff --git a/src/soc/intel/apollolake/Makefile.inc b/src/soc/intel/apollolake/Makefile.inc
index 4e05726..6bbfe57 100644
--- a/src/soc/intel/apollolake/Makefile.inc
+++ b/src/soc/intel/apollolake/Makefile.inc
@@ -25,6 +25,7 @@ romstage-y += memmap.c
romstage-y += mmap_boot.c
smm-y += placeholders.c
+ramstage-y += car_teardown.c
ramstage-y += cpu.c
ramstage-y += chip.c
ramstage-y += placeholders.c
diff --git a/src/soc/intel/apollolake/bootblock/cache_as_ram.S b/src/soc/intel/apollolake/bootblock/cache_as_ram.S
index c81fe0a..cc021dc 100644
--- a/src/soc/intel/apollolake/bootblock/cache_as_ram.S
+++ b/src/soc/intel/apollolake/bootblock/cache_as_ram.S
@@ -16,8 +16,7 @@
#include <cpu/x86/cache.h>
#include <cpu/x86/cr.h>
#include <cpu/x86/post_code.h>
-
-#define EVICT_CTL_MSR 0x2e0
+#include <soc/cpu.h>
.global bootblock_pre_c_entry
bootblock_pre_c_entry:
@@ -96,7 +95,7 @@ clear_var_mtrr:
mov %eax, %cr0
/* Disable cache eviction (setup stage) */
- mov $EVICT_CTL_MSR, %ecx
+ mov $MSR_EVICT_CTL, %ecx
rdmsr
or $0x1, %eax
wrmsr
@@ -112,7 +111,7 @@ clear_var_mtrr:
post_code(0x27)
/* Disable cache eviction (run stage) */
- mov $EVICT_CTL_MSR, %ecx
+ mov $MSR_EVICT_CTL, %ecx
rdmsr
or $0x2, %eax
wrmsr
diff --git a/src/soc/intel/apollolake/car_teardown.c b/src/soc/intel/apollolake/car_teardown.c
new file mode 100644
index 0000000..d2df7f7
--- /dev/null
+++ b/src/soc/intel/apollolake/car_teardown.c
@@ -0,0 +1,135 @@
+/*
+ * Cache-as-ram teardown for apollolake SOC. See detailed explanation below.
+ *
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2015 Intel Corp.
+ * (Written by Alexandru Gagniuc <alexandrux.gagniuc(a)intel.com> for Intel Corp.)
+ * (Written by Andrey Petrov <andrey.petrov(a)intel.com> for Intel Corp.)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <bootstate.h>
+#include <console/console.h>
+#include <cpu/cpu.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/mtrr.h>
+#include <cpu/x86/msr.h>
+#include <cpu/x86/tsc.h>
+#include <cbmem.h>
+#include <memrange.h>
+#include <symbols.h>
+
+#define EVICT_CTL_MSR 0x2e0
+#define CACHELINE_SIZE 64
+/*
+ * The CAR teardown on apollolake is more complicated than the standard x86
+ * teardown paths because romstage executes in CAR. That means romstage cannot
+ * do the teardown. For performance reasons, the cache is also used as a backing
+ * store for RAM after raminit.
+ *
+ * This results in a cache with both a CAR region, and memory-backed regions:
+ * - Invalidating the entire cache will evict stack and code that has not yet
+ * been commited, to RAM, resulting in a crash.
+ * - A 'wbinvd' will result in a crash during the write-back phase because
+ * the CAR region has no backing store.
+ *
+ * This teardown path resolves these problems by first flushing important data
+ * out of cache, to memory. After this operation, it is safe to invalidate the
+ * entire cache, which is then followed by standard MTRR housekeeping.
+ *
+ * For performance reasons, only the memory regions which may have been written
+ * to are flushed. This includes ramstage code and cbmem. A complete flush of
+ * all RAM ranges would take several seconds.
+ */
+
+static void clflush(uintptr_t addr)
+{
+ __asm__ volatile ("clflush (%0)"::"r" (addr));
+}
+
+static void clflush_mem_range(uintptr_t start, uintptr_t end)
+{
+ end = ALIGN_UP(end, CACHELINE_SIZE);
+
+ for (start = ALIGN_DOWN(start, CACHELINE_SIZE); start < end;
+ start += CACHELINE_SIZE)
+ clflush(start);
+}
+
+static void flush_ram_cache_and_invalidate(void)
+{
+ uintptr_t cbmem_base;
+ size_t cbmem_size;
+ struct memranges ctx;
+ struct range_entry entries[3];
+ const struct range_entry *r;
+ const struct cbmem_entry *fsp_rsvd_mem;
+
+ memranges_init_empty(&ctx, entries, ARRAY_SIZE(entries));
+
+ /* Figure out where ramstage resides; this is inclusive of the stack */
+ memranges_insert(&ctx, (uintptr_t)&_program, _program_size, 0);
+
+ /* It's okay if CBMEM and ramstage overlap. */
+ cbmem_region_used(&cbmem_base, &cbmem_size);
+ memranges_insert(&ctx, cbmem_base, cbmem_size, 0);
+
+ /*
+ * FSP reserved memory was written before caching was enabled. Thus it
+ * does not need to be flushed. This saves about 10ms of boot time.
+ */
+ fsp_rsvd_mem = cbmem_entry_find(CBMEM_ID_FSP_RESERVED_MEMORY);
+ if (fsp_rsvd_mem) {
+ memranges_create_hole(&ctx,
+ (uintptr_t)cbmem_entry_start(fsp_rsvd_mem),
+ cbmem_entry_size(fsp_rsvd_mem)
+ );
+ }
+
+ /* Flush ramstage code and stack */
+ memranges_each_entry(r, &ctx)
+ clflush_mem_range(range_entry_base(r), range_entry_end(r));
+
+ /* Now that important data is flushed, invalidate all caches */
+ invd();
+}
+
+static void disable_car_region_and_no_evict_mode(void)
+{
+ msr_t msr;
+
+ /* Disable variable and fixed MTRRs */
+ msr.lo = msr.hi = 0;
+ wrmsr(MTRR_DEF_TYPE_MSR, msr);
+ /* Disable CAR MTRR */
+ wrmsr(MTRR_PHYS_BASE(0), msr);
+ wrmsr(MTRR_PHYS_MASK(0), msr);
+
+ /* Switch out of "no evict" mode */
+ msr = rdmsr(EVICT_CTL_MSR);
+ msr.lo &= ~2;
+ wrmsr(EVICT_CTL_MSR, msr);
+
+ msr.lo &= ~1;
+ wrmsr(EVICT_CTL_MSR, msr);
+
+ /* Re-enable remaining MTRRs */
+ msr.lo = MTRR_DEF_TYPE_EN;
+ msr.hi = 0;
+ wrmsr(MTRR_DEF_TYPE_MSR, msr);
+}
+
+static void tear_down_car(void *unused_arg)
+{
+ (void) unused_arg;
+
+ flush_ram_cache_and_invalidate();
+ disable_car_region_and_no_evict_mode();
+}
+
+BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_ENTRY, tear_down_car, NULL);
diff --git a/src/soc/intel/apollolake/include/soc/cpu.h b/src/soc/intel/apollolake/include/soc/cpu.h
index 765be70..b7b2fcc 100644
--- a/src/soc/intel/apollolake/include/soc/cpu.h
+++ b/src/soc/intel/apollolake/include/soc/cpu.h
@@ -13,19 +13,22 @@
#ifndef _SOC_APOLLOLAKE_CPU_H_
#define _SOC_APOLLOLAKE_CPU_H_
+#ifndef __ASSEMBLER__
#include <cpu/x86/msr.h>
#include <device/device.h>
+void apollolake_init_cpus(struct device *dev);
+#endif
+
#define CPUID_APOLLOLAKE_A0 0x506c8
#define CPUID_APOLLOLAKE_B0 0x506c9
#define MSR_PLATFORM_INFO 0xce
#define MSR_POWER_MISC 0x120
#define MSR_CORE_THREAD_COUNT 0x35
+#define MSR_EVICT_CTL 0x2e0
#define BASE_CLOCK_MHZ 100
-void apollolake_init_cpus(struct device *dev);
-
#endif /* _SOC_APOLLOLAKE_CPU_H_ */