summaryrefslogtreecommitdiff
path: root/src/soc/intel/common
diff options
context:
space:
mode:
authorSubrata Banik <subratabanik@google.com>2023-02-24 19:49:20 +0000
committerLean Sheng Tan <sheng.tan@9elements.com>2023-03-13 14:11:31 +0000
commitbc8bbeed3b8a1e1ee60b0e184e2afb6603721c34 (patch)
treeefebd7eaf8b3f38a48366419c4b3938086af9d02 /src/soc/intel/common
parent182cf7f1204917663be189f63b308a096f0d4799 (diff)
soc/intel/cmn/tom: Cache TOM region early
This patch implements a module that can store the top_of_ram (TOM) address into non-volatile space (CMOS) during the first boot and use it across all consecutive boot. As top_of_ram address is not known until FSP-M has exited, it results into lacking of MTRR programming to cache the 16 MB TOM, hence accessing that range during FSP-M and/or late romstage causing long access times. Purpose of this driver code is to cache the TOM (with a fixed size of 16MB) for all consecutive boots even before calling into the FSP. Otherwise, this range remains un-cached until postcar boot stage updates the MTRR programming. FSP-M and late romstage uses this uncached TOM range for various purposes (like relocating services between SPI mapped cached memory to DRAM based uncache memory) hence having the ability to cache this range beforehand would help to optimize the boot time (more than 50ms as applicable). TEST=Able to build and boot google/rex to ChromeOS. Without this patch: 950:calling FspMemoryInit               936,811 (19,941)   951:returning from FspMemoryInit        1,041,935 (105,123) With this patch:  950:calling FspMemoryInit               905,108 (20,103)   951:returning from FspMemoryInit        987,038 (81,929) Change-Id: I29d3e1df91c6057280bdf7fb6a4a356db31a408f Signed-off-by: Subrata Banik <subratabanik@google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/73272 Reviewed-by: Kapil Porwal <kapilporwal@google.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Arthur Heymans <arthur@aheymans.xyz> Reviewed-by: Lean Sheng Tan <sheng.tan@9elements.com>
Diffstat (limited to 'src/soc/intel/common')
-rw-r--r--src/soc/intel/common/basecode/include/intelbasecode/tom.h14
-rw-r--r--src/soc/intel/common/basecode/tom/Kconfig15
-rw-r--r--src/soc/intel/common/basecode/tom/Makefile.inc2
-rw-r--r--src/soc/intel/common/basecode/tom/tom.c127
4 files changed, 158 insertions, 0 deletions
diff --git a/src/soc/intel/common/basecode/include/intelbasecode/tom.h b/src/soc/intel/common/basecode/include/intelbasecode/tom.h
new file mode 100644
index 0000000000..d78ecd1a60
--- /dev/null
+++ b/src/soc/intel/common/basecode/include/intelbasecode/tom.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef SOC_INTEL_COMMON_BASECODE_TOM_H
+#define SOC_INTEL_COMMON_BASECODE_TOM_H
+
+#include <types.h>
+
+/* Early caching of TOM region */
+void early_tom_enable_cache_range(void);
+
+/* Update the TOM if required based on the input TOM address */
+void update_tom(uint32_t addr);
+
+#endif
diff --git a/src/soc/intel/common/basecode/tom/Kconfig b/src/soc/intel/common/basecode/tom/Kconfig
new file mode 100644
index 0000000000..ff91725a52
--- /dev/null
+++ b/src/soc/intel/common/basecode/tom/Kconfig
@@ -0,0 +1,15 @@
+config SOC_INTEL_COMMON_BASECODE_TOM
+ bool
+ default n
+ help
+ Driver code to store the top_of_ram (TOM) address into
+ non-volatile space (CMOS) during the first boot and use
+ it across all consecutive boot.
+
+ Purpose of this driver code is to cache the TOM (with a
+ fixed size) for all consecutive boots even before calling
+ into the FSP. Otherwise, this range remains un-cached until postcar
+ boot stage updates the MTRR programming. FSP-M and late romstage
+ uses this uncached TOM range for various purposes and having the
+ ability to cache this range beforehand would help to optimize the boot
+ time (more than 50ms).
diff --git a/src/soc/intel/common/basecode/tom/Makefile.inc b/src/soc/intel/common/basecode/tom/Makefile.inc
new file mode 100644
index 0000000000..2ebf4bb25f
--- /dev/null
+++ b/src/soc/intel/common/basecode/tom/Makefile.inc
@@ -0,0 +1,2 @@
+## SPDX-License-Identifier: GPL-2.0-only
+romstage-$(CONFIG_SOC_INTEL_COMMON_BASECODE_TOM) += tom.c
diff --git a/src/soc/intel/common/basecode/tom/tom.c b/src/soc/intel/common/basecode/tom/tom.c
new file mode 100644
index 0000000000..de696d555d
--- /dev/null
+++ b/src/soc/intel/common/basecode/tom/tom.c
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <console/console.h>
+#include <cpu/x86/mtrr.h>
+#include <ip_checksum.h>
+#include <intelbasecode/tom.h>
+#include <pc80/mc146818rtc.h>
+#include <stdint.h>
+
+/* We need a region in CMOS to store the TOM address */
+
+#define TOM_SIGNATURE 0x5F544F4D /* '_TOM' */
+
+#define TOM_CMOS_OFFSET 0x64
+
+/*
+ * Address of the tom_cmos_offset byte in CMOS. Should be reserved
+ * in mainboards' cmos.layout and not covered by checksum.
+ */
+
+#if CONFIG(USE_OPTION_TABLE)
+#include "option_table.h"
+#if CMOS_VSTART_tom_cmos_offset != TOM_CMOS_OFFSET * 8
+#error "CMOS start for TOM_CMOS is not correct, check your cmos.layout"
+#endif
+#if CMOS_VLEN_tom_cmos_offset != 12
+#error "CMOS length for TOM_CMOS bytes are not correct, check your cmos.layout"
+#endif
+#endif
+
+struct tom_table {
+ uint32_t signature;
+ uint32_t addr;
+ uint16_t checksum;
+} __packed;
+
+/* Read and validate tom_table structure from CMOS */
+static int tom_cmos_read(struct tom_table *tom)
+{
+ u8 i, *p;
+ u16 csum;
+
+ for (p = (u8 *)tom, i = 0; i < sizeof(*tom); i++, p++)
+ *p = cmos_read(TOM_CMOS_OFFSET + i);
+
+ /* Verify signature */
+ if (tom->signature != TOM_SIGNATURE) {
+ printk(BIOS_DEBUG, "tom_table invalid signature\n");
+ return -1;
+ }
+
+ /* Verify checksum over signature and counter only */
+ csum = compute_ip_checksum(tom, offsetof(struct tom_table, checksum));
+
+ if (csum != tom->checksum) {
+ printk(BIOS_DEBUG, "tom_table checksum mismatch\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Write tom_table structure to CMOS */
+static void tom_cmos_write(struct tom_table *tom)
+{
+ u8 i, *p;
+
+ /* Checksum over signature and counter only */
+ tom->checksum = compute_ip_checksum(
+ tom, offsetof(struct tom_table, checksum));
+
+ for (p = (u8 *)tom, i = 0; i < sizeof(*tom); i++, p++)
+ cmos_write(*p, TOM_CMOS_OFFSET + i);
+}
+
+/* Update the TOM if required based on the input TOM address */
+void update_tom(uint32_t addr)
+{
+ struct tom_table tom;
+
+ /* Read and increment boot count */
+ if (tom_cmos_read(&tom) < 0) {
+ /* Structure invalid, re-initialize */
+ tom.signature = TOM_SIGNATURE;
+ tom.addr = 0;
+ }
+
+ /* Update TOM if required */
+ if (tom.addr == addr)
+ return;
+
+ tom.addr = addr;
+
+ /* Write the new count to CMOS */
+ tom_cmos_write(&tom);
+
+ printk(BIOS_DEBUG, "Updated the TOM address into CMOS 0x%x\n", tom.addr);
+}
+
+static uint32_t get_tom_addr(void)
+{
+ struct tom_table tom;
+
+ if (tom_cmos_read(&tom) < 0)
+ return 0;
+
+ return tom.addr;
+}
+
+/* Early caching of TOM region */
+void early_tom_enable_cache_range(void)
+{
+ uint32_t tom = get_tom_addr();
+ if (!tom)
+ return;
+
+ int mtrr = get_free_var_mtrr();
+ if (mtrr == -1) {
+ printk(BIOS_WARNING, "tom_table update failure due to no free MTRR available!\n");
+ return;
+ }
+ /*
+ * We need to make sure late romstage (including FSP-M post mem) will be run
+ * cached. Caching 16MB below TOM is a safe to cover late romstage.
+ */
+ set_var_mtrr(mtrr, tom - 16 * MiB, 16 * MiB, MTRR_TYPE_WRBACK);
+}