Commit 95ffa243 authored by Yinghai Lu's avatar Yinghai Lu Committed by Thomas Gleixner

x86: mtrr cleanup for converting continuous to discrete layout, v8

some BIOS like to use continus MTRR layout, and X driver can not add
WB entries for graphical cards when 4g or more RAM installed.

the patch will change MTRR to discrete.

mtrr_chunk_size= could be used to have smaller continuous block to hold holes.
default is 256m, could be set according to size of graphics card memory.

mtrr_gran_size= could be used to send smallest mtrr block to avoid run out of MTRRs

v2: fix -1 for UC checking
v3: default to disable, and need use enable_mtrr_cleanup to enable this feature
    skip the var state change warning.
    remove next_basek in range_to_mtrr()
v4: correct warning mask.
v5: CONFIG_MTRR_SANITIZER
v6: fix 1g, 2g, 512 aligment with extra hole
v7: gran_sizek to prevent running out of MTRRs.
v8: fix hole_basek caculation caused when removing next_basek
    gran_sizek using when basek is 0.

need to apply
	[PATCH] x86: fix trimming e820 with MTRR holes.
right after this one.
Signed-off-by: default avatarYinghai Lu <yhlu.kernel@gmail.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 0dbfafa5
...@@ -599,6 +599,20 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -599,6 +599,20 @@ and is between 256 and 4096 characters. It is defined in the file
See drivers/char/README.epca and See drivers/char/README.epca and
Documentation/digiepca.txt. Documentation/digiepca.txt.
disable_mtrr_cleanup [X86]
enable_mtrr_cleanup [X86]
The kernel tries to adjust MTRR layout from continuous
to discrete, to make X server driver able to add WB
entry later. This parameter enables/disables that.
mtrr_chunk_size=nn[KMG] [X86]
used for mtrr cleanup. It is largest continous chunk
that could hold holes aka. UC entries.
mtrr_gran_size=nn[KMG] [X86]
used for mtrr cleanup. It is granity of mtrr block.
Big value could prevent small alignment use up MTRRs.
disable_mtrr_trim [X86, Intel and AMD only] disable_mtrr_trim [X86, Intel and AMD only]
By default the kernel will trim any uncacheable By default the kernel will trim any uncacheable
memory out of your available memory pool based on memory out of your available memory pool based on
......
...@@ -1092,6 +1092,32 @@ config MTRR ...@@ -1092,6 +1092,32 @@ config MTRR
See <file:Documentation/mtrr.txt> for more information. See <file:Documentation/mtrr.txt> for more information.
config MTRR_SANITIZER
def_bool y
prompt "MTRR cleanup support"
depends on MTRR
help
Convert MTRR layout from continuous to discrete, so some X driver
could add WB entries.
Say N here if you see bootup problems (boot crash, boot hang,
spontaneous reboots).
Could be disabled with disable_mtrr_cleanup. Also mtrr_chunk_size
could be used to send largest mtrr entry size for continuous block
to hold holes (aka. UC entries)
If unsure, say Y.
config MTRR_SANITIZER_ENABLE_DEFAULT
def_bool y
prompt "Enable MTRR cleanup by default"
depends on MTRR_SANITIZER
help
Enable mtrr cleanup by default
If unsure, say Y.
config X86_PAT config X86_PAT
bool bool
prompt "x86 PAT support" prompt "x86 PAT support"
......
...@@ -37,7 +37,7 @@ static struct fixed_range_block fixed_range_blocks[] = { ...@@ -37,7 +37,7 @@ static struct fixed_range_block fixed_range_blocks[] = {
static unsigned long smp_changes_mask; static unsigned long smp_changes_mask;
static struct mtrr_state mtrr_state = {}; static struct mtrr_state mtrr_state = {};
static int mtrr_state_set; static int mtrr_state_set;
static u64 tom2; u64 mtrr_tom2;
#undef MODULE_PARAM_PREFIX #undef MODULE_PARAM_PREFIX
#define MODULE_PARAM_PREFIX "mtrr." #define MODULE_PARAM_PREFIX "mtrr."
...@@ -139,8 +139,8 @@ u8 mtrr_type_lookup(u64 start, u64 end) ...@@ -139,8 +139,8 @@ u8 mtrr_type_lookup(u64 start, u64 end)
} }
} }
if (tom2) { if (mtrr_tom2) {
if (start >= (1ULL<<32) && (end < tom2)) if (start >= (1ULL<<32) && (end < mtrr_tom2))
return MTRR_TYPE_WRBACK; return MTRR_TYPE_WRBACK;
} }
...@@ -158,6 +158,20 @@ get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr) ...@@ -158,6 +158,20 @@ get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr)
rdmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); rdmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
} }
/* fill the MSR pair relating to a var range */
void fill_mtrr_var_range(unsigned int index,
u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi)
{
struct mtrr_var_range *vr;
vr = mtrr_state.var_ranges;
vr[index].base_lo = base_lo;
vr[index].base_hi = base_hi;
vr[index].mask_lo = mask_lo;
vr[index].mask_hi = mask_hi;
}
static void static void
get_fixed_ranges(mtrr_type * frs) get_fixed_ranges(mtrr_type * frs)
{ {
...@@ -216,10 +230,10 @@ void __init get_mtrr_state(void) ...@@ -216,10 +230,10 @@ void __init get_mtrr_state(void)
unsigned low, high; unsigned low, high;
/* TOP_MEM2 */ /* TOP_MEM2 */
rdmsr(MSR_K8_TOP_MEM2, low, high); rdmsr(MSR_K8_TOP_MEM2, low, high);
tom2 = high; mtrr_tom2 = high;
tom2 <<= 32; mtrr_tom2 <<= 32;
tom2 |= low; mtrr_tom2 |= low;
tom2 &= 0xffffff8000000ULL; mtrr_tom2 &= 0xffffff8000000ULL;
} }
if (mtrr_show) { if (mtrr_show) {
int high_width; int high_width;
...@@ -251,9 +265,9 @@ void __init get_mtrr_state(void) ...@@ -251,9 +265,9 @@ void __init get_mtrr_state(void)
else else
printk(KERN_INFO "MTRR %u disabled\n", i); printk(KERN_INFO "MTRR %u disabled\n", i);
} }
if (tom2) { if (mtrr_tom2) {
printk(KERN_INFO "TOM2: %016llx aka %lldM\n", printk(KERN_INFO "TOM2: %016llx aka %lldM\n",
tom2, tom2>>20); mtrr_tom2, mtrr_tom2>>20);
} }
} }
mtrr_state_set = 1; mtrr_state_set = 1;
......
This diff is collapsed.
...@@ -81,6 +81,8 @@ void set_mtrr_done(struct set_mtrr_context *ctxt); ...@@ -81,6 +81,8 @@ void set_mtrr_done(struct set_mtrr_context *ctxt);
void set_mtrr_cache_disable(struct set_mtrr_context *ctxt); void set_mtrr_cache_disable(struct set_mtrr_context *ctxt);
void set_mtrr_prepare_save(struct set_mtrr_context *ctxt); void set_mtrr_prepare_save(struct set_mtrr_context *ctxt);
void fill_mtrr_var_range(unsigned int index,
u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi);
void get_mtrr_state(void); void get_mtrr_state(void);
extern void set_mtrr_ops(struct mtrr_ops * ops); extern void set_mtrr_ops(struct mtrr_ops * ops);
...@@ -92,6 +94,7 @@ extern struct mtrr_ops * mtrr_if; ...@@ -92,6 +94,7 @@ extern struct mtrr_ops * mtrr_if;
#define use_intel() (mtrr_if && mtrr_if->use_intel_if == 1) #define use_intel() (mtrr_if && mtrr_if->use_intel_if == 1)
extern unsigned int num_var_ranges; extern unsigned int num_var_ranges;
extern u64 mtrr_tom2;
void mtrr_state_warn(void); void mtrr_state_warn(void);
const char *mtrr_attrib_to_str(int x); const char *mtrr_attrib_to_str(int x);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment