summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cpu/x86/Kconfig5
-rw-r--r--src/cpu/x86/mtrr/mtrr.c59
-rw-r--r--src/include/cpu/x86/mtrr.h16
3 files changed, 79 insertions, 1 deletions
diff --git a/src/cpu/x86/Kconfig b/src/cpu/x86/Kconfig
index 8f05bf3b04..4c5176b693 100644
--- a/src/cpu/x86/Kconfig
+++ b/src/cpu/x86/Kconfig
@@ -56,8 +56,11 @@ config LOGICAL_CPUS
default y
config CACHE_ROM
- bool
+ bool "Allow for caching system ROM."
default n
+ help
+ When selected a variable range MTRR is allocated for coreboot and
+ the bootloader enables caching of the system ROM for faster access.
config SMM_TSEG
bool
diff --git a/src/cpu/x86/mtrr/mtrr.c b/src/cpu/x86/mtrr/mtrr.c
index 74aae64a89..dad10292a9 100644
--- a/src/cpu/x86/mtrr/mtrr.c
+++ b/src/cpu/x86/mtrr/mtrr.c
@@ -163,6 +163,16 @@ static struct memranges *get_physical_address_space(void)
memranges_add_resources(addr_space, mask, match,
MTRR_TYPE_WRCOMB);
+#if CONFIG_CACHE_ROM
+ /* Add a write-protect region covering the ROM size
+ * when CONFIG_CACHE_ROM is enabled. The ROM is assumed
+ * to be located at 4GiB - rom size. */
+ resource_t rom_base = RANGE_TO_PHYS_ADDR(
+ RANGE_4GB - PHYS_TO_RANGE_ADDR(CONFIG_ROM_SIZE));
+ memranges_insert(addr_space, rom_base, CONFIG_ROM_SIZE,
+ MTRR_TYPE_WRPROT);
+#endif
+
/* The address space below 4GiB is special. It needs to be
* covered entirly by range entries so that MTRR calculations
* can be properly done for the full 32-bit address space.
@@ -335,6 +345,44 @@ void x86_setup_fixed_mtrrs(void)
enable_fixed_mtrr();
}
+/* Keep track of the MTRR that covers the ROM for caching purposes. */
+#if CONFIG_CACHE_ROM
+static long rom_cache_mtrr = -1;
+
+void x86_mtrr_enable_rom_caching(void)
+{
+ msr_t msr_val;
+ unsigned long index;
+
+ if (rom_cache_mtrr < 0)
+ return;
+
+ index = rom_cache_mtrr;
+ disable_cache();
+ msr_val = rdmsr(MTRRphysBase_MSR(index));
+ msr_val.lo &= ~0xff;
+ msr_val.lo |= MTRR_TYPE_WRPROT;
+ wrmsr(MTRRphysBase_MSR(index), msr_val);
+ enable_cache();
+}
+
+void x86_mtrr_disable_rom_caching(void)
+{
+ msr_t msr_val;
+ unsigned long index;
+
+ if (rom_cache_mtrr < 0)
+ return;
+
+ index = rom_cache_mtrr;
+ disable_cache();
+ msr_val = rdmsr(MTRRphysBase_MSR(index));
+ msr_val.lo &= ~0xff;
+ wrmsr(MTRRphysBase_MSR(index), msr_val);
+ enable_cache();
+}
+#endif
+
struct var_mtrr_state {
struct memranges *addr_space;
int above4gb;
@@ -382,6 +430,17 @@ static void write_var_mtrr(struct var_mtrr_state *var_state,
mask = (1ULL << var_state->address_bits) - 1;
rsize = rsize & mask;
+#if CONFIG_CACHE_ROM
+ /* CONFIG_CACHE_ROM allocates an MTRR specifically for allowing
+ * one to turn on caching for faster ROM access. However, it is
+ * left to the MTRR callers to enable it. */
+ if (mtrr_type == MTRR_TYPE_WRPROT) {
+ mtrr_type = MTRR_TYPE_UNCACHEABLE;
+ if (rom_cache_mtrr < 0)
+ rom_cache_mtrr = var_state->mtrr_index;
+ }
+#endif
+
printk(BIOS_DEBUG, "MTRR: %d base 0x%016llx mask 0x%016llx type %d\n",
var_state->mtrr_index, rbase, rsize, mtrr_type);
diff --git a/src/include/cpu/x86/mtrr.h b/src/include/cpu/x86/mtrr.h
index 618a93c44e..bff736d296 100644
--- a/src/include/cpu/x86/mtrr.h
+++ b/src/include/cpu/x86/mtrr.h
@@ -52,6 +52,10 @@
* of the nature of the global MTRR enable flag. Therefore, all direct
* or indirect callers of enable_fixed_mtrr() should ensure that the
* variable MTRR MSRs do not contain bad ranges.
+ * 3. If CONFIG_CACHE_ROM is selected an MTRR is allocated for enabling
+ * the caching of the ROM. However, it is set to uncacheable (UC). It
+ * is the responsiblity of the caller to enable it by calling
+ * x86_mtrr_enable_rom_caching().
*/
void x86_setup_mtrrs(void);
/*
@@ -67,6 +71,18 @@ void x86_setup_fixed_mtrrs(void);
/* Set up fixed MTRRs but do not enable them. */
void x86_setup_fixed_mtrrs_no_enable(void);
int x86_mtrr_check(void);
+/* ROM caching can be used after variable MTRRs are set up. Beware that
+ * enabling CONFIG_CACHE_ROM will eat through quite a few MTRRs based on
+ * one's IO hole size and WRCOMB resources. Be sure to check the console
+ * log when enabling CONFIG_CACHE_ROM or adding WRCOMB resources. */
+#if CONFIG_CACHE_ROM
+void x86_mtrr_enable_rom_caching(void);
+void x86_mtrr_disable_rom_caching(void);
+#else
+static inline void x86_mtrr_enable_rom_caching(void) {}
+static inline void x86_mtrr_disable_rom_caching(void) {}
+#endif /* CONFIG_CACHE_ROM */
+
#endif
#if !defined(CONFIG_RAMTOP)