summaryrefslogtreecommitdiff
path: root/arch/x86/cpu
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2015-01-01 16:18:07 -0700
committerSimon Glass <sjg@chromium.org>2015-01-13 07:25:00 -0800
commitaff2523f6998dca1f667aa0d26cc8f351c5628dc (patch)
treeae1694272e3fd7124f83e2a5730755943d041dbd /arch/x86/cpu
parent3a5659f7cfc0fd99b57fe2ed9e4a9ebde7cf8491 (diff)
x86: Add support for MTRRs
Memory Type Range Registers are used to tell the CPU whether memory is cacheable and if so the cache write mode to use. Clean up the existing header file to follow style, and remove the unneeded code. These can speed up booting so should be supported. Add these to global_data so they can be requested while booting. We will apply the changes during relocation (in a later commit). Signed-off-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'arch/x86/cpu')
-rw-r--r--arch/x86/cpu/Makefile1
-rw-r--r--arch/x86/cpu/coreboot/coreboot.c22
-rw-r--r--arch/x86/cpu/ivybridge/car.S12
-rw-r--r--arch/x86/cpu/mtrr.c81
4 files changed, 98 insertions, 18 deletions
diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile
index 5033d2b757..62e43c04e5 100644
--- a/arch/x86/cpu/Makefile
+++ b/arch/x86/cpu/Makefile
@@ -17,5 +17,6 @@ obj-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += ivybridge/
obj-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += ivybridge/
obj-$(CONFIG_INTEL_QUEENSBAY) += queensbay/
obj-y += lapic.o
+obj-y += mtrr.o
obj-$(CONFIG_PCI) += pci.o
obj-y += turbo.o
diff --git a/arch/x86/cpu/coreboot/coreboot.c b/arch/x86/cpu/coreboot/coreboot.c
index cfacc05875..6d06d5af19 100644
--- a/arch/x86/cpu/coreboot/coreboot.c
+++ b/arch/x86/cpu/coreboot/coreboot.c
@@ -15,6 +15,7 @@
#include <asm/cache.h>
#include <asm/cpu.h>
#include <asm/io.h>
+#include <asm/mtrr.h>
#include <asm/arch/tables.h>
#include <asm/arch/sysinfo.h>
#include <asm/arch/timestamp.h>
@@ -64,11 +65,6 @@ int board_eth_init(bd_t *bis)
return pci_eth_init(bis);
}
-#define MTRR_TYPE_WP 5
-#define MTRRcap_MSR 0xfe
-#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
-#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
-
void board_final_cleanup(void)
{
/* Un-cache the ROM so the kernel has one
@@ -77,15 +73,17 @@ void board_final_cleanup(void)
* Coreboot should have assigned this to the
* top available variable MTRR.
*/
- u8 top_mtrr = (native_read_msr(MTRRcap_MSR) & 0xff) - 1;
- u8 top_type = native_read_msr(MTRRphysBase_MSR(top_mtrr)) & 0xff;
+ u8 top_mtrr = (native_read_msr(MTRR_CAP_MSR) & 0xff) - 1;
+ u8 top_type = native_read_msr(MTRR_PHYS_BASE_MSR(top_mtrr)) & 0xff;
/* Make sure this MTRR is the correct Write-Protected type */
- if (top_type == MTRR_TYPE_WP) {
- disable_caches();
- wrmsrl(MTRRphysBase_MSR(top_mtrr), 0);
- wrmsrl(MTRRphysMask_MSR(top_mtrr), 0);
- enable_caches();
+ if (top_type == MTRR_TYPE_WRPROT) {
+ struct mtrr_state state;
+
+ mtrr_open(&state);
+ wrmsrl(MTRR_PHYS_BASE_MSR(top_mtrr), 0);
+ wrmsrl(MTRR_PHYS_MASK_MSR(top_mtrr), 0);
+ mtrr_close(&state);
}
/* Issue SMI to Coreboot to lock down ME and registers */
diff --git a/arch/x86/cpu/ivybridge/car.S b/arch/x86/cpu/ivybridge/car.S
index dca68e4144..72b22ea9e4 100644
--- a/arch/x86/cpu/ivybridge/car.S
+++ b/arch/x86/cpu/ivybridge/car.S
@@ -61,7 +61,7 @@ clear_mtrrs:
post_code(POST_CAR_MTRR)
/* Configure the default memory type to uncacheable */
- movl $MTRRdefType_MSR, %ecx
+ movl $MTRR_DEF_TYPE_MSR, %ecx
rdmsr
andl $(~0x00000cff), %eax
wrmsr
@@ -76,16 +76,16 @@ clear_mtrrs:
post_code(POST_CAR_BASE_ADDRESS)
/* Set Cache-as-RAM mask */
movl $(MTRR_PHYS_MASK_MSR(0)), %ecx
- movl $(~(CACHE_AS_RAM_SIZE - 1) | MTRRphysMaskValid), %eax
+ movl $(~(CACHE_AS_RAM_SIZE - 1) | MTRR_PHYS_MASK_VALID), %eax
movl $CPU_PHYSMASK_HI, %edx
wrmsr
post_code(POST_CAR_MASK)
/* Enable MTRR */
- movl $MTRRdefType_MSR, %ecx
+ movl $MTRR_DEF_TYPE_MSR, %ecx
rdmsr
- orl $MTRRdefTypeEn, %eax
+ orl $MTRR_DEF_TYPE_EN, %eax
wrmsr
/* Enable cache (CR0.CD = 0, CR0.NW = 0) */
@@ -130,7 +130,7 @@ clear_mtrrs:
movl $MTRR_PHYS_MASK_MSR(1), %ecx
movl $CPU_PHYSMASK_HI, %edx
- movl $(~(CONFIG_XIP_ROM_SIZE - 1) | MTRRphysMaskValid), %eax
+ movl $(~(CONFIG_XIP_ROM_SIZE - 1) | MTRR_PHYS_MASK_VALID), %eax
wrmsr
post_code(POST_CAR_ROM_CACHE)
@@ -141,7 +141,7 @@ clear_mtrrs:
xorl %edx, %edx
wrmsr
movl $MTRR_PHYS_MASK_MSR(2), %ecx
- movl $(CACHE_MRC_MASK | MTRRphysMaskValid), %eax
+ movl $(CACHE_MRC_MASK | MTRR_PHYS_MASK_VALID), %eax
movl $CPU_PHYSMASK_HI, %edx
wrmsr
#endif
diff --git a/arch/x86/cpu/mtrr.c b/arch/x86/cpu/mtrr.c
new file mode 100644
index 0000000000..d5a825d181
--- /dev/null
+++ b/arch/x86/cpu/mtrr.c
@@ -0,0 +1,81 @@
+/*
+ * (C) Copyright 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Memory Type Range Regsters - these are used to tell the CPU whether
+ * memory is cacheable and if so the cache write mode to use.
+ *
+ * These can speed up booting. See the mtrr command.
+ *
+ * Reference: Intel Architecture Software Developer's Manual, Volume 3:
+ * System Programming
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/msr.h>
+#include <asm/mtrr.h>
+
+/* Prepare to adjust MTRRs */
+void mtrr_open(struct mtrr_state *state)
+{
+ state->enable_cache = dcache_status();
+
+ if (state->enable_cache)
+ disable_caches();
+ state->deftype = native_read_msr(MTRR_DEF_TYPE_MSR);
+ wrmsrl(MTRR_DEF_TYPE_MSR, state->deftype & ~MTRR_DEF_TYPE_EN);
+}
+
+/* Clean up after adjusting MTRRs, and enable them */
+void mtrr_close(struct mtrr_state *state)
+{
+ wrmsrl(MTRR_DEF_TYPE_MSR, state->deftype | MTRR_DEF_TYPE_EN);
+ if (state->enable_cache)
+ enable_caches();
+}
+
+int mtrr_commit(bool do_caches)
+{
+ struct mtrr_request *req = gd->arch.mtrr_req;
+ struct mtrr_state state;
+ uint64_t mask;
+ int i;
+
+ mtrr_open(&state);
+ for (i = 0; i < gd->arch.mtrr_req_count; i++, req++) {
+ mask = ~(req->size - 1);
+ mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1;
+ wrmsrl(MTRR_PHYS_BASE_MSR(i), req->start | req->type);
+ wrmsrl(MTRR_PHYS_MASK_MSR(i), mask | MTRR_PHYS_MASK_VALID);
+ }
+
+ /* Clear the ones that are unused */
+ for (; i < MTRR_COUNT; i++)
+ wrmsrl(MTRR_PHYS_MASK_MSR(i), 0);
+ mtrr_close(&state);
+
+ return 0;
+}
+
+int mtrr_add_request(int type, uint64_t start, uint64_t size)
+{
+ struct mtrr_request *req;
+ uint64_t mask;
+
+ if (gd->arch.mtrr_req_count == MAX_MTRR_REQUESTS)
+ return -ENOSPC;
+ req = &gd->arch.mtrr_req[gd->arch.mtrr_req_count++];
+ req->type = type;
+ req->start = start;
+ req->size = size;
+ debug("%d: type=%d, %08llx %08llx\n", gd->arch.mtrr_req_count - 1,
+ req->type, req->start, req->size);
+ mask = ~(req->size - 1);
+ mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1;
+ mask |= MTRR_PHYS_MASK_VALID;
+ debug(" %016llx %016llx\n", req->start | req->type, mask);
+
+ return 0;
+}