Stefan Reinauer (stefan.reinauer(a)coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/765
-gerrit
commit 21277f9883218c89fba15ebfbac7fcf3236fe9a8
Author: Duncan Laurie <dlaurie(a)chromium.org>
Date: Mon Jan 9 22:05:18 2012 -0800
Make MTRR min hole alignment 64MB
This affects the algorithm when determining when to
transform a range into a larger range with a hole.
It is needed when for when I switch on an 8MB TSEG
and cause the memory maps to go crazy.
Also add header defines for the SMRR.
Change-Id: I1a06ccc28ef139cc79f655a8b19fd3533aca0401
Signed-off-by: Duncan Laurie <dlaurie(a)google.com>
---
src/cpu/x86/mtrr/mtrr.c | 9 ++++++---
src/include/cpu/x86/mtrr.h | 3 +++
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/src/cpu/x86/mtrr/mtrr.c b/src/cpu/x86/mtrr/mtrr.c
index 5f5e02b..ed7d93b 100644
--- a/src/cpu/x86/mtrr/mtrr.c
+++ b/src/cpu/x86/mtrr/mtrr.c
@@ -265,13 +265,16 @@ static unsigned int range_to_mtrr(unsigned int reg,
return reg;
}
- if (above4gb == 2 && type == MTRR_TYPE_WRBACK && range_sizek % 0x4000) {
+#define MIN_ALIGN 0x10000 /* 64MB */
+
+ if (above4gb == 2 && type == MTRR_TYPE_WRBACK &&
+ range_sizek > MIN_ALIGN && range_sizek % MIN_ALIGN) {
/*
- * If this range is not divisible by 16MB then instead
+ * If this range is not divisible then instead
* make a larger range and carve out an uncached hole.
*/
hole_startk = range_startk + range_sizek;
- hole_sizek = 0x4000 - (range_sizek % 0x4000);
+ hole_sizek = MIN_ALIGN - (range_sizek % MIN_ALIGN);
range_sizek += hole_sizek;
}
diff --git a/src/include/cpu/x86/mtrr.h b/src/include/cpu/x86/mtrr.h
index 62cb8b7..8b5cc28 100644
--- a/src/include/cpu/x86/mtrr.h
+++ b/src/include/cpu/x86/mtrr.h
@@ -17,6 +17,9 @@
#define MTRRdefTypeEn (1 << 11)
#define MTRRdefTypeFixEn (1 << 10)
+#define SMRRphysBase_MSR 0x1f2
+#define SMRRphysMask_MSR 0x1f3
+
#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
Stefan Reinauer (stefan.reinauer(a)coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/769
-gerrit
commit a3b2c440baca27f9275b2e4bb7cb591c565fc08d
Author: Duncan Laurie <dlaurie(a)chromium.org>
Date: Tue Jan 17 09:03:11 2012 -0800
Prepare the BIOS data areas before device init.
Since we do not run option roms in normal mode nothing was
initializing the BDA/EBDA and yet Linux depends very much
on it having sane values here. For the most part the kernel
tries to work around this not being initialized, but every
once in awhile (1/300 boots or so) it would end up reading
something that looked sane from BDA but was not and then
it would panic.
In this change the EBDA is unconditionally setup before devices
are initialized. I'm not set on the location in dev_initialize()
but there does not seem to be another place to hook it in so
that it runs just once for ALL platforms regardless of whether
they use option roms or not. (possibly hardwaremain?)
The EBDA setup code has been moved into its own location in
arch/x86/lib/ebda.c so it can be compiled in even if the option
rom code is not.
The low memory size is still set to 1MB which is enough to make
linux happy without having to hook into each mainboard to get a
more appropriate value. The setup_ebda() function takes inputs
so it could be changed for a mainboard if needed.
OLD/BROKEN would read garbage. Examples from different boots:
ebda_addr=0x75e80 lowmem=0x1553400
ebda_addr=0x5e080 lowmem=0x3e51400
ebda_addr=0x7aa80 lowmem=0x2f8a800
NEW/FIXED now reads consistent values:
ebda_addr=0xf6000 lowmem=0x100000
Change-Id: I6cb79f0e3e43cc65f7e5fe98b6cad1a557ccd949
Signed-off-by: Duncan Laurie <dlaurie(a)google.com>
---
src/arch/x86/include/arch/ebda.h | 37 +++++++++++++++++++++++++++++
src/arch/x86/lib/Makefile.inc | 1 +
src/arch/x86/lib/ebda.c | 48 ++++++++++++++++++++++++++++++++++++++
src/devices/device.c | 8 ++++++
src/devices/oprom/x86.c | 16 ------------
5 files changed, 94 insertions(+), 16 deletions(-)
diff --git a/src/arch/x86/include/arch/ebda.h b/src/arch/x86/include/arch/ebda.h
new file mode 100644
index 0000000..1de6097
--- /dev/null
+++ b/src/arch/x86/include/arch/ebda.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2012 The Chromium OS Authors. All rights reserved.
+ *
+ * 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; version 2 of
+ * the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#ifndef __ARCH_EBDA_H
+#define __ARCH_EBDA_H
+
+#define X86_BDA_SIZE 0x200
+#define X86_BDA_BASE 0x400
+#define X86_EBDA_SEGMENT 0x40e
+#define X86_EBDA_LOWMEM 0x413
+
+#define DEFAULT_EBDA_LOWMEM (1024 << 10)
+#define DEFAULT_EBDA_SEGMENT 0xF600
+#define DEFAULT_EBDA_SIZE 0x400
+
+void setup_ebda(u32 low_memory_size, u16 ebda_segment, u16 ebda_size);
+void setup_default_ebda(void);
+
+#endif
diff --git a/src/arch/x86/lib/Makefile.inc b/src/arch/x86/lib/Makefile.inc
index 96fb9b0..8f5fd5f 100644
--- a/src/arch/x86/lib/Makefile.inc
+++ b/src/arch/x86/lib/Makefile.inc
@@ -8,6 +8,7 @@ ramstage-y += exception.c
ramstage-$(CONFIG_IOAPIC) += ioapic.c
ramstage-y += memset.c
ramstage-y += memcpy.c
+ramstage-y += ebda.c
romstage-y += romstage_console.c
romstage-y += cbfs_and_run.c
diff --git a/src/arch/x86/lib/ebda.c b/src/arch/x86/lib/ebda.c
new file mode 100644
index 0000000..faf1451
--- /dev/null
+++ b/src/arch/x86/lib/ebda.c
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2012 The Chromium OS Authors. All rights reserved.
+ *
+ * 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; version 2 of
+ * the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <arch/io.h>
+#include <arch/ebda.h>
+
+void setup_ebda(u32 low_memory_size, u16 ebda_segment, u16 ebda_size)
+{
+ if (!low_memory_size || !ebda_segment || !ebda_size)
+ return;
+
+ /* clear BIOS DATA AREA */
+ memset((void *)X86_BDA_BASE, 0, X86_BDA_SIZE);
+
+ write16(X86_EBDA_LOWMEM, (low_memory_size >> 10));
+ write16(X86_EBDA_SEGMENT, ebda_segment);
+
+ /* Set up EBDA */
+ memset((void *)(ebda_segment << 4), 0, ebda_size);
+ write16((ebda_segment << 4), (ebda_size >> 10));
+}
+
+void setup_default_ebda(void)
+{
+ setup_ebda(DEFAULT_EBDA_LOWMEM,
+ DEFAULT_EBDA_SEGMENT,
+ DEFAULT_EBDA_SIZE);
+}
diff --git a/src/devices/device.c b/src/devices/device.c
index 0d2bf8f..0e9c39e 100644
--- a/src/devices/device.c
+++ b/src/devices/device.c
@@ -41,6 +41,9 @@
#include <stdlib.h>
#include <string.h>
#include <smp/spinlock.h>
+#if CONFIG_ARCH_X86
+#include <arch/ebda.h>
+#endif
/** Linked list of ALL devices */
struct device *all_devices = &dev_root;
@@ -1102,6 +1105,11 @@ void dev_initialize(void)
printk(BIOS_INFO, "Initializing devices...\n");
+#if CONFIG_ARCH_X86
+ /* Ensure EBDA is prepared before Option ROMs. */
+ setup_default_ebda();
+#endif
+
/* First call the mainboard init. */
init_dev(&dev_root);
diff --git a/src/devices/oprom/x86.c b/src/devices/oprom/x86.c
index 0c15b15..564017d 100644
--- a/src/devices/oprom/x86.c
+++ b/src/devices/oprom/x86.c
@@ -40,19 +40,6 @@ void (*realmode_interrupt)(u32 intno, u32 eax, u32 ebx, u32 ecx, u32 edx,
u32 esi, u32 edi) __attribute__((regparm(0))) =
(void *)&__realmode_interrupt;
-static void setup_bda(void)
-{
- /* clear BIOS DATA AREA */
- memset((void *)0x400, 0, 0x200);
-
- write16(0x413, FAKE_MEMORY_SIZE / 1024);
- write16(0x40e, INITIAL_EBDA_SEGMENT);
-
- /* Set up EBDA */
- memset((void *)(INITIAL_EBDA_SEGMENT << 4), 0, INITIAL_EBDA_SIZE);
- write16((INITIAL_EBDA_SEGMENT << 4) + 0x0, INITIAL_EBDA_SIZE / 1024);
-}
-
static void setup_rombios(void)
{
const char date[] = "06/11/99";
@@ -272,9 +259,6 @@ void run_bios(struct device *dev, unsigned long addr)
*/
setup_i8259();
- /* Set up BIOS Data Area */
- setup_bda();
-
/* Set up some legacy information in the F segment */
setup_rombios();
Stefan Reinauer (stefan.reinauer(a)coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/766
-gerrit
commit 099a1d65203f9e0529dcfa986639ce91ffdec05d
Author: Duncan Laurie <dlaurie(a)chromium.org>
Date: Mon Jan 9 22:11:25 2012 -0800
Add Kconfig options to enable TSEG and set a size
Future CPUs will require TSEG use for SMM
Change-Id: I1432569ece4371d6e12c997e90d66c175fa54c5c
Signed-off-by: Duncan Laurie <dlaurie(a)google.com>
---
src/cpu/x86/Kconfig | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/src/cpu/x86/Kconfig b/src/cpu/x86/Kconfig
index 6894622..0eaee2e 100644
--- a/src/cpu/x86/Kconfig
+++ b/src/cpu/x86/Kconfig
@@ -43,3 +43,11 @@ config LOGICAL_CPUS
config CACHE_ROM
bool
default n
+
+config SMM_TSEG
+ bool
+ default n
+
+config SMM_TSEG_SIZE
+ hex
+ default 0
Stefan Reinauer (stefan.reinauer(a)coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/770
-gerrit
commit 38173d059962cb600361cbe48af36b11765d73c3
Author: Duncan Laurie <dlaurie(a)chromium.org>
Date: Wed Jan 18 10:05:18 2012 -0800
Don't re-init EBDA in S3 resume path.
I forgot to implement this the first time around.
It does not seem to cause noticeable problems but
in heavy suspend/resume testing I saw a suspicious
crash in the kernel when trying to bring one of the
CPUs back online.
Change-Id: I950ac260f251e2683693d9bd20a0dd5e041aa26e
Signed-off-by: Duncan Laurie <dlaurie(a)google.com>
---
src/arch/x86/lib/ebda.c | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/src/arch/x86/lib/ebda.c b/src/arch/x86/lib/ebda.c
index faf1451..fb407b6 100644
--- a/src/arch/x86/lib/ebda.c
+++ b/src/arch/x86/lib/ebda.c
@@ -23,9 +23,18 @@
#include <string.h>
#include <arch/io.h>
#include <arch/ebda.h>
+#if CONFIG_HAVE_ACPI_RESUME
+#include <arch/acpi.h>
+#endif
void setup_ebda(u32 low_memory_size, u16 ebda_segment, u16 ebda_size)
{
+#if CONFIG_HAVE_ACPI_RESUME
+ /* Skip in S3 resume path */
+ if (acpi_slp_type == 3)
+ return;
+#endif
+
if (!low_memory_size || !ebda_segment || !ebda_size)
return;
Stefan Reinauer (stefan.reinauer(a)coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/761
-gerrit
commit ea52a9429656c8b5004da212f4c2cc1fcfb52db9
Author: Duncan Laurie <dlaurie(a)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(a)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