[coreboot] Patch set updated for coreboot: 2b09353 MTRR: add alternate allocation method for odd memory maps

Stefan Reinauer (stefan.reinauer@coreboot.org) gerrit at coreboot.org
Fri Mar 9 17:01:41 CET 2012


Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/761

-gerrit

commit 2b09353c1277488f6174ba1be2d5bc0d3fea573d
Author: Duncan Laurie <dlaurie at chromium.org>
Date:   Thu Dec 22 10:59:40 2011 -0800

    MTRR: add alternate allocation method for odd memory maps
    
    With >= 4GB memory installed we get a memory map split in the middle
    due to remap that has boundaries that are inconveniently aligned for
    MTRRs due to the various UMA regions.
    
    0000MB-2780MB  2780MB  RAM     (writeback)
    2780MB-2782MB     2MB  TSEG    (uncached/SMRR)
    2782MB-2784MB     2MB  GFX GTT (uncached)
    2784MB-2816MB    32MB  GFX UMA (uncached)
    2816MB-4096MB  1280MB  EMPTY   (N/A)
    4096MB-5368MB  1272MB  RAM     (writeback)
    5368MB-5376MB     8MB  ME UMA  (uncached)
    
    The default MTRR allocation method of trying to cover everything
    with one MTRR and then carve out a single uncached region does
    not work for the GPU aperture which needs write-combining type,
    and it also has issues trying to cover the uneven boundaries
    in the avaiable variable MTRRs.
    
    My goal was to make a minimal set of changes and avoid modifying
    behavior on existing systems with an algorithm that is not always
    optimal for a typical memory layout.  So the flag 'above4gb=2'
    will change these allocation behaviors:
    
    1) Detect the number of available variable MTRRs rather than
    limiting to hardcoded value.  We need every last MTRR.
    
    2) Don't try to cover all RAM with one MTRR, instead let each
    RAM region get covered independently.
    
    3) Don't assume uma_memory_base is part of the last region
    and increase the size of that region.  In this case the UMA
    region is carved out from the lower memory region and it is
    already declared as part of the ram region.
    
    4) If a memory region can't be covered with MTRRs >= 16MB then
    instead make a larger region and trim it with uncached MTRRs.
    
    Change-Id: I5a60a44ab6d3ae2f46ea6ffa9e3677aaad2485eb
    Signed-off-by: Duncan Laurie <dlaurie at google.com>
---
 src/cpu/x86/mtrr/mtrr.c |   52 ++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 45 insertions(+), 7 deletions(-)

diff --git a/src/cpu/x86/mtrr/mtrr.c b/src/cpu/x86/mtrr/mtrr.c
index 9015ad4..8dccfef 100644
--- a/src/cpu/x86/mtrr/mtrr.c
+++ b/src/cpu/x86/mtrr/mtrr.c
@@ -179,6 +179,18 @@ static inline unsigned int fls(unsigned int x)
 #endif
 #define MTRRS        (BIOS_MTRRS + OS_MTRRS)
 
+static int total_mtrrs = MTRRS;
+static int bios_mtrrs = BIOS_MTRRS;
+
+static void detect_var_mtrrs(void)
+{
+	msr_t msr;
+
+	msr = rdmsr(MTRRcap_MSR);
+
+	total_mtrrs = msr.lo & 0xff;
+	bios_mtrrs = total_mtrrs - 2;
+}
 
 static void set_fixed_mtrrs(unsigned int first, unsigned int last, unsigned char type)
 {
@@ -235,6 +247,8 @@ static unsigned int range_to_mtrr(unsigned int reg,
 	unsigned long next_range_startk, unsigned char type,
 	unsigned int address_bits, unsigned int above4gb)
 {
+	unsigned long hole_startk = 0, hole_sizek = 0;
+
 	if (!range_sizek) {
 		/* If there's no MTRR hole, this function will bail out
 		 * here when called for the hole.
@@ -243,7 +257,7 @@ static unsigned int range_to_mtrr(unsigned int reg,
 		return reg;
 	}
 
-	if (reg >= BIOS_MTRRS) {
+	if (reg >= bios_mtrrs) {
 		printk(BIOS_ERR, "Warning: Out of MTRRs for base: %4ldMB, range: %ldMB, type %s\n",
 				range_startk >>10, range_sizek >> 10,
 				(type==MTRR_TYPE_UNCACHEABLE)?"UC":
@@ -251,6 +265,16 @@ static unsigned int range_to_mtrr(unsigned int reg,
 		return reg;
 	}
 
+	if (above4gb == 2 && type == MTRR_TYPE_WRBACK && range_sizek % 0x4000) {
+		/*
+		 * If this range is not divisible by 16MB then instead
+		 * make a larger range and carve out an uncached hole.
+		 */
+		hole_startk = range_startk + range_sizek;
+		hole_sizek = 0x4000 - (range_sizek % 0x4000);
+		range_sizek += hole_sizek;
+	}
+
 	while(range_sizek) {
 		unsigned long max_align, align;
 		unsigned long sizek;
@@ -274,11 +298,20 @@ static unsigned int range_to_mtrr(unsigned int reg,
 			set_var_mtrr(reg++, range_startk, sizek, type, address_bits);
 		range_startk += sizek;
 		range_sizek -= sizek;
-		if (reg >= BIOS_MTRRS) {
+		if (reg >= bios_mtrrs) {
 			printk(BIOS_ERR, "Running out of variable MTRRs!\n");
 			break;
 		}
 	}
+
+	if (hole_sizek) {
+		printk(BIOS_DEBUG, "Adding hole at %ldMB-%ldMB\n",
+		       hole_startk, hole_startk + hole_sizek);
+		reg = range_to_mtrr(reg, hole_startk, hole_sizek,
+			      next_range_startk, MTRR_TYPE_UNCACHEABLE,
+			      address_bits, above4gb);
+	}
+
 	return reg;
 }
 
@@ -325,7 +358,7 @@ void set_var_mtrr_resource(void *gp, struct device *dev, struct resource *res)
 {
 	struct var_mtrr_state *state = gp;
 	unsigned long basek, sizek;
-	if (state->reg >= BIOS_MTRRS)
+	if (state->reg >= bios_mtrrs)
 		return;
 	basek = resk(res->base);
 	sizek = resk(res->size);
@@ -341,7 +374,7 @@ void set_var_mtrr_resource(void *gp, struct device *dev, struct resource *res)
 	/* Write the range mtrrs */
 	if (state->range_sizek != 0) {
 #if CONFIG_VAR_MTRR_HOLE
-		if (state->hole_sizek == 0) {
+		if (state->hole_sizek == 0 && state->above4gb != 2) {
 			/* We need to put that on to hole */
 			unsigned long endk = basek + sizek;
 			state->hole_startk = state->range_startk + state->range_sizek;
@@ -424,6 +457,10 @@ void x86_setup_var_mtrrs(unsigned int address_bits, unsigned int above4gb)
 	var_state.address_bits = address_bits;
 	var_state.above4gb = above4gb;
 
+	/* Detect number of variable MTRRs */
+	if (above4gb == 2)
+		detect_var_mtrrs();
+
 	search_global_resources(
 		IORESOURCE_MEM | IORESOURCE_CACHEABLE, IORESOURCE_MEM | IORESOURCE_CACHEABLE,
 		set_var_mtrr_resource, &var_state);
@@ -435,7 +472,8 @@ void x86_setup_var_mtrrs(unsigned int address_bits, unsigned int above4gb)
 	} else {
 #if CONFIG_VAR_MTRR_HOLE
 		// Increase the base range and set up UMA as an UC hole instead
-		var_state.range_sizek += (uma_memory_size >> 10);
+		if (above4gb != 2)
+			var_state.range_sizek += (uma_memory_size >> 10);
 
 		var_state.hole_startk = (uma_memory_base >> 10);
 		var_state.hole_sizek = (uma_memory_size >> 10);
@@ -454,7 +492,7 @@ void x86_setup_var_mtrrs(unsigned int address_bits, unsigned int above4gb)
 	printk(BIOS_DEBUG, "DONE variable MTRRs\n");
 	printk(BIOS_DEBUG, "Clear out the extra MTRR's\n");
 	/* Clear out the extra MTRR's */
-	while(var_state.reg < MTRRS) {
+	while(var_state.reg < total_mtrrs) {
 		set_var_mtrr(var_state.reg++, 0, 0, 0, var_state.address_bits);
 	}
 
@@ -463,7 +501,7 @@ void x86_setup_var_mtrrs(unsigned int address_bits, unsigned int above4gb)
 	 * complete ROM now that we actually have RAM.
 	 */
 	if (boot_cpu() && (acpi_slp_type != 3)) {
-		set_var_mtrr(7, (4096-4)*1024, 4*1024,
+		set_var_mtrr(total_mtrrs-1, (4096-4)*1024, 4*1024,
 			MTRR_TYPE_WRPROT, address_bits);
 	}
 #endif




More information about the coreboot mailing list