Commit f0348c43 authored by Yinghai Lu's avatar Yinghai Lu Committed by Ingo Molnar

x86: MTRR workaround for system with stange var MTRRs

Impact: don't trim e820 according to wrong mtrr

Ozan reports that his server emits strange warning.
it turns out the BIOS sets the MTRRs incorrectly.

Ignore those strange ranges, and don't trim e820,
just emit one warning about BIOS
Reported-by: default avatarOzan Çağlayan <ozan@pardus.org.tr>
Signed-off-by: default avatarYinghai Lu <yinghai@kernel.org>
LKML-Reference: <49BEE1E7.7020706@kernel.org>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent d4c90e37
...@@ -189,6 +189,17 @@ x86_get_mtrr_mem_range(struct res_range *range, int nr_range, ...@@ -189,6 +189,17 @@ x86_get_mtrr_mem_range(struct res_range *range, int nr_range,
if (!size) if (!size)
continue; continue;
base = range_state[i].base_pfn; base = range_state[i].base_pfn;
if (base < (1<<(20-PAGE_SHIFT)) && mtrr_state.have_fixed &&
(mtrr_state.enabled & 1)) {
/* Var MTRR contains UC entry below 1M? Skip it: */
printk(KERN_WARNING "WARNING: BIOS bug: VAR MTRR %d "
"contains strange UC entry under 1M, check "
"with your system vendor!\n", i);
if (base + size <= (1<<(20-PAGE_SHIFT)))
continue;
size -= (1<<(20-PAGE_SHIFT)) - base;
base = 1<<(20-PAGE_SHIFT);
}
subtract_range(range, base, base + size - 1); subtract_range(range, base, base + size - 1);
} }
if (extra_remove_size) if (extra_remove_size)
......
...@@ -574,7 +574,7 @@ struct mtrr_value { ...@@ -574,7 +574,7 @@ struct mtrr_value {
unsigned long lsize; unsigned long lsize;
}; };
static struct mtrr_value mtrr_state[MTRR_MAX_VAR_RANGES]; static struct mtrr_value mtrr_value[MTRR_MAX_VAR_RANGES];
static int mtrr_save(struct sys_device * sysdev, pm_message_t state) static int mtrr_save(struct sys_device * sysdev, pm_message_t state)
{ {
...@@ -582,9 +582,9 @@ static int mtrr_save(struct sys_device * sysdev, pm_message_t state) ...@@ -582,9 +582,9 @@ static int mtrr_save(struct sys_device * sysdev, pm_message_t state)
for (i = 0; i < num_var_ranges; i++) { for (i = 0; i < num_var_ranges; i++) {
mtrr_if->get(i, mtrr_if->get(i,
&mtrr_state[i].lbase, &mtrr_value[i].lbase,
&mtrr_state[i].lsize, &mtrr_value[i].lsize,
&mtrr_state[i].ltype); &mtrr_value[i].ltype);
} }
return 0; return 0;
} }
...@@ -594,11 +594,11 @@ static int mtrr_restore(struct sys_device * sysdev) ...@@ -594,11 +594,11 @@ static int mtrr_restore(struct sys_device * sysdev)
int i; int i;
for (i = 0; i < num_var_ranges; i++) { for (i = 0; i < num_var_ranges; i++) {
if (mtrr_state[i].lsize) if (mtrr_value[i].lsize)
set_mtrr(i, set_mtrr(i,
mtrr_state[i].lbase, mtrr_value[i].lbase,
mtrr_state[i].lsize, mtrr_value[i].lsize,
mtrr_state[i].ltype); mtrr_value[i].ltype);
} }
return 0; return 0;
} }
......
...@@ -79,6 +79,7 @@ extern struct mtrr_ops * mtrr_if; ...@@ -79,6 +79,7 @@ extern struct mtrr_ops * mtrr_if;
extern unsigned int num_var_ranges; extern unsigned int num_var_ranges;
extern u64 mtrr_tom2; extern u64 mtrr_tom2;
extern struct mtrr_state_type mtrr_state;
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